diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyExtractor.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java similarity index 88% rename from libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyExtractor.java rename to libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java index b3f8196f1..becc41534 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyExtractor.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java @@ -1,6 +1,6 @@ package com.jpexs.decompiler.flash.iggy; -import com.jpexs.decompiler.flash.SWF; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.File; @@ -22,9 +22,9 @@ import java.util.logging.Logger; * Based of works of somebody called eternity. * */ -public class IggyExtractor extends AbstractDataStream implements AutoCloseable { +public class IggyFile extends AbstractDataStream implements AutoCloseable { - final static Logger LOGGER = Logger.getLogger(IggyExtractor.class.getName()); + final static Logger LOGGER = Logger.getLogger(IggyFile.class.getName()); private RandomAccessFile raf; private IggyHeader header; @@ -37,7 +37,7 @@ public class IggyExtractor extends AbstractDataStream implements AutoCloseable { private List namesAndTagLists = new ArrayList<>(); private List> tagDataTables = new ArrayList<>(); - public IggyExtractor(File file) throws IOException { + public IggyFile(File file) throws IOException { raf = new RandomAccessFile(file, "r"); header = new IggyHeader(this); for (int i = 0; i < header.getNumSubfiles(); i++) { @@ -71,7 +71,7 @@ public class IggyExtractor extends AbstractDataStream implements AutoCloseable { ByteArrayDataStream flashStream = flashStreams.get(i); List offsets = offsetTables.get(i); List tagIds = namesAndTagLists.get(i).getTagIds(); - List tagExtended = namesAndTagLists.get(i).getTagIdsExtendedInfo(); + List tagExtended = namesAndTagLists.get(i).getTagIdsExtraInfo(); int offsetIndex = 3; //0 = SWF name, 1 = UI16 zero, 2 = tag list List tagDataStreams = new ArrayList<>(); @@ -183,7 +183,7 @@ public class IggyExtractor extends AbstractDataStream implements AutoCloseable { public static void extractIggyFile(File iggyFile, File extractDir) throws IOException { final String FILENAME_FORMAT = "index%d_type%d.bin"; - try (IggyExtractor ir = new IggyExtractor(iggyFile)) { + try (IggyFile ir = new IggyFile(iggyFile)) { for (int i = 0; i < ir.getNumEntries(); i++) { IggySubFileEntry entry = ir.getSubFileEntry(i); try (FileOutputStream fos = new FileOutputStream(new File(extractDir, String.format(FILENAME_FORMAT, i, entry.type)))) { @@ -695,12 +695,67 @@ public class IggyExtractor extends AbstractDataStream implements AutoCloseable { return namesAndTagLists.get(swfIndex).getTagIds(); } - public List getSwfTagExtraInfos(int swfIndex) { - return namesAndTagLists.get(swfIndex).getTagIdsExtendedInfo(); + public Integer getSwfTagId(int swfIndex, int tagIndex) { + return namesAndTagLists.get(swfIndex).getTagIds().get(tagIndex); } - public SWF extractSwf(int swfIndex) { - return null; //TODO + public List getSwfTagExtraInfos(int swfIndex) { + return namesAndTagLists.get(swfIndex).getTagIdsExtraInfo(); + } + + public Long getSwfTagExtraInfo(int swfIndex, int tagIndex) { + return namesAndTagLists.get(swfIndex).getTagIdsExtraInfo().get(tagIndex); + } + + public long getSwfXMin(int swfIndex) { + return headers.get(swfIndex).getXMin(); + } + + public long getSwfYMin(int swfIndex) { + return headers.get(swfIndex).getYMin(); + } + + public long getSwfXMax(int swfIndex) { + return headers.get(swfIndex).getXMax(); + } + + public long getSwfYMax(int swfIndex) { + return headers.get(swfIndex).getYMax(); + } + + public float getSwfFrameRate(int swfIndex) { + return headers.get(swfIndex).getFrameRate(); + } + + public int getSwfTagCount(int swfIndex) { + return getSwfTagIds(swfIndex).size(); + } + + public AbstractDataStream gettSwfTagDataStream(int swfIndex, int tagIndex) { + return tagDataTables.get(swfIndex).get(tagIndex); + } + + public InputStream getSwfTagInputStream(int swfIndex, int tagIndex) { + return new ByteArrayInputStream(getSwfTagData(swfIndex, tagIndex)); + } + + public byte[] getSwfTagData(int swfIndex, int tagIndex) { + AbstractDataStream stream = gettSwfTagDataStream(swfIndex, tagIndex); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int bufSize = 4096; + //Assuming available() result is always known (= not returning null) + while (stream.available() > 0) { + if (stream.available() < bufSize) { + bufSize = (int) (long) stream.available(); + } + try { + byte[] buffer = stream.readBytes(bufSize); + baos.write(buffer); + } catch (IOException iex) { + //ignore + } + } + return baos.toByteArray(); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java index 599aded20..3422e2e12 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java @@ -51,7 +51,7 @@ public class IggyFlashHeader32 implements IggyFlashHeaderInterface { long unk_38; @IggyFieldType(DataType.uint32_t) long unk_3C; - float frame_rate; + float frameRate; @IggyFieldType(DataType.uint32_t) long unk_44; @IggyFieldType(DataType.uint32_t) @@ -80,11 +80,6 @@ public class IggyFlashHeader32 implements IggyFlashHeaderInterface { long unk_78; // Maybe number of classes / as3 names @IggyFieldType(DataType.uint32_t) long unk_7C; - @IggyFieldType(value = DataType.uint16_t, count = 20) - String name; - - List tagIds = new ArrayList<>(); - List tagIdsExtendedInfo = new ArrayList<>(); // 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. @@ -114,7 +109,7 @@ public class IggyFlashHeader32 implements IggyFlashHeaderInterface { unk_34 = stream.readUI32(); unk_38 = stream.readUI32(); unk_3C = stream.readUI32(); - frame_rate = stream.readFloat(); + frameRate = stream.readFloat(); unk_44 = stream.readUI32(); unk_48 = stream.readUI32(); unk_4C = stream.readUI32(); @@ -130,26 +125,6 @@ public class IggyFlashHeader32 implements IggyFlashHeaderInterface { unk_74 = stream.readUI32(); unk_78 = stream.readUI32(); unk_7C = stream.readUI32(); - StringBuilder nameBuilder = new StringBuilder(); - do { - char c = (char) stream.readUI16(); - if (c == '\0') { - break; - } - nameBuilder.append(c); - } while (true); - name = nameBuilder.toString(); - - while (true) { - long typeLen = stream.readUI16(); //TODO: check whether it's really UI16 - 64bit works with UI32 - if (typeLen == 0) { - break; - } - long tagLength = stream.readUI16(); - int tagType = (int) ((typeLen >>> 6) + 10) & 0x3FF; - tagIds.add(tagType); - tagIdsExtendedInfo.add(tagLength); - } } @Override @@ -178,7 +153,7 @@ public class IggyFlashHeader32 implements IggyFlashHeaderInterface { 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("frame_rate ").append(frame_rate).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"); @@ -193,19 +168,32 @@ public class IggyFlashHeader32 implements IggyFlashHeaderInterface { 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("name ").append(name).append("\r\n"); - Map map = Tag.getKnownClasses(); - sb.append("tags:").append("\r\n"); - for (int i = 0; i < tagIds.size(); i++) { - TagTypeInfo tti = map.get(tagIds.get(i)); - sb.append(" tag ").append(tagIds.get(i)).append(":").append(tti == null ? "?" : tti.getName()); - if (tagIdsExtendedInfo.get(i) > 0) { - sb.append(" (special: ").append(tagIdsExtendedInfo.get(i)).append(")"); - } - sb.append("\r\n"); - } sb.append("]"); return sb.toString(); } + @Override + public long getXMin() { + return xmin; + } + + @Override + public long getYMin() { + return ymin; + } + + @Override + public long getXMax() { + return xmax; + } + + @Override + public long getYMax() { + return ymax; + } + + @Override + public float getFrameRate() { + return frameRate; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java index 99c9c0cf4..024c1fedd 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 @@ -48,7 +48,7 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { long unk_50; @IggyFieldType(DataType.uint32_t) long unk_54; - float frame_rate; + float frameRate; @IggyFieldType(DataType.uint32_t) long unk_5C; @IggyFieldType(DataType.uint64_t) @@ -127,7 +127,7 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { unk_4C = stream.readUI32(); unk_50 = stream.readUI32(); unk_54 = stream.readUI32(); - frame_rate = stream.readFloat(); + frameRate = stream.readFloat(); unk_5C = stream.readUI32(); unk_60 = stream.readUI64(); unk_68 = stream.readUI64(); @@ -169,7 +169,7 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { 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("frameRate ").append(frameRate).append("\r\n"); sb.append("unk_5C ").append(unk_5C).append("\r\n"); sb.append("unk_60 ").append(unk_60).append("\r\n"); sb.append("unk_68 ").append(unk_68).append("\r\n"); @@ -189,4 +189,29 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { } + @Override + public long getXMin() { + return xmin; + } + + @Override + public long getYMin() { + return ymin; + } + + @Override + public long getXMax() { + return xmax; + } + + @Override + public long getYMax() { + return ymax; + } + + @Override + public float getFrameRate() { + return frameRate; + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeaderInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeaderInterface.java index b98193d81..fc07b1ba6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeaderInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeaderInterface.java @@ -6,4 +6,13 @@ package com.jpexs.decompiler.flash.iggy; */ public interface IggyFlashHeaderInterface extends StructureInterface { + public long getXMin(); + + public long getYMin(); + + public long getXMax(); + + public long getYMax(); + + public float getFrameRate(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyNameAndTagList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyNameAndTagList.java index c06b3d4ba..dc907af8f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyNameAndTagList.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyNameAndTagList.java @@ -19,12 +19,12 @@ public class IggyNameAndTagList implements StructureInterface { private List tagIds; @IggyArrayFieldType(value = DataType.uint16_t) - private List tagIdsExtendedInfo; + private List tagIdsExtraInfo; public IggyNameAndTagList(String name, List tagIds, List tagIdsExtendedInfo) { this.name = name; this.tagIds = tagIds; - this.tagIdsExtendedInfo = tagIdsExtendedInfo; + this.tagIdsExtraInfo = tagIdsExtendedInfo; } public IggyNameAndTagList(AbstractDataStream stream) throws IOException { @@ -44,7 +44,7 @@ public class IggyNameAndTagList implements StructureInterface { name = nameBuilder.toString(); tagIds = new ArrayList<>(); - tagIdsExtendedInfo = new ArrayList<>(); + tagIdsExtraInfo = new ArrayList<>(); while (true) { long typeLen = stream.readUI32(); if (typeLen == 0) { @@ -53,7 +53,7 @@ public class IggyNameAndTagList implements StructureInterface { long tagLength = stream.readUI32(); int tagType = (int) ((typeLen >>> 6) + 10) & 0x3FF; tagIds.add(tagType); - tagIdsExtendedInfo.add(tagLength); + tagIdsExtraInfo.add(tagLength); } } @@ -65,8 +65,8 @@ public class IggyNameAndTagList implements StructureInterface { return tagIds; } - public List getTagIdsExtendedInfo() { - return tagIdsExtendedInfo; + public List getTagIdsExtraInfo() { + return tagIdsExtraInfo; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyToSwfConvertor.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyToSwfConvertor.java new file mode 100644 index 000000000..f45633ea2 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyToSwfConvertor.java @@ -0,0 +1,82 @@ +package com.jpexs.decompiler.flash.iggy.conversion; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFCompression; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.iggy.IggyFile; +import com.jpexs.decompiler.flash.iggy.IggyFlashHeaderInterface; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.UnknownTag; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.helpers.ByteArrayRange; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * TODO: TEST!!! + * + * @author JPEXS + */ +public class IggyToSwfConvertor { + + public 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 void exportAllSwfsToDir(IggyFile file, File outputDir) throws IOException { + for (int swfIndex = 0; swfIndex < file.getSwfCount(); swfIndex++) { + exportSwfToDir(file, swfIndex, outputDir); + } + } + + public 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 void exportSwfToFile(IggyFile file, int swfIndex, File outputFile) throws IOException { + try (FileOutputStream fos = new FileOutputStream(outputFile)) { + exportSwf(file, swfIndex, fos); + } + } + + public void exportSwf(IggyFile file, int swfIndex, OutputStream output) throws IOException { + SWF swf = getSwf(file, swfIndex); + swf.saveTo(output); + } + + public SWF getSwf(IggyFile file, int swfIndex) { + SWF swf = new SWF(); + swf.compression = SWFCompression.NONE; + swf.frameCount = 1; //FIXME!! + 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 = 9; //FIXME + for (int tagIndex = 0; tagIndex < file.getSwfTagCount(swfIndex); tagIndex++) { + byte[] data = file.getSwfTagData(swfIndex, tagIndex); + int dataLength = data.length; + int tagLength = dataLength; + int tagID = file.getSwfTagId(swfIndex, tagIndex); + long tagExtra = file.getSwfTagExtraInfo(swfIndex, tagIndex); + try { + swf.addTag(new UnknownTag(new SWFInputStream(swf, data), tagID, new ByteArrayRange(data))); + } catch (IOException ex) { + //ignored + } + } + return swf; + } +}