Iggy to SWF export class, refactorings

This commit is contained in:
Jindra Petřík
2016-11-23 13:16:32 +01:00
parent 6007e94414
commit 589227fc80
6 changed files with 217 additions and 58 deletions

View File

@@ -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<IggyNameAndTagList> namesAndTagLists = new ArrayList<>();
private List<List<ByteArrayDataStream>> 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<Long> offsets = offsetTables.get(i);
List<Integer> tagIds = namesAndTagLists.get(i).getTagIds();
List<Long> tagExtended = namesAndTagLists.get(i).getTagIdsExtendedInfo();
List<Long> tagExtended = namesAndTagLists.get(i).getTagIdsExtraInfo();
int offsetIndex = 3; //0 = SWF name, 1 = UI16 zero, 2 = tag list
List<ByteArrayDataStream> 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<Long> 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<Long> 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();
}
}

View File

@@ -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<Integer> tagIds = new ArrayList<>();
List<Long> 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<Integer, TagTypeInfo> 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;
}
}

View File

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

View File

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

View File

@@ -19,12 +19,12 @@ public class IggyNameAndTagList implements StructureInterface {
private List<Integer> tagIds;
@IggyArrayFieldType(value = DataType.uint16_t)
private List<Long> tagIdsExtendedInfo;
private List<Long> tagIdsExtraInfo;
public IggyNameAndTagList(String name, List<Integer> tagIds, List<Long> 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<Long> getTagIdsExtendedInfo() {
return tagIdsExtendedInfo;
public List<Long> getTagIdsExtraInfo() {
return tagIdsExtraInfo;
}
@Override

View File

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