Font offsets, other refactorings

This commit is contained in:
Jindra Petřík
2016-11-23 22:03:56 +01:00
parent 810ddca7e8
commit 3225c62564
7 changed files with 137 additions and 236 deletions

View File

@@ -16,6 +16,8 @@ public abstract class AbstractDataStream {
*/
public abstract Long available();
public abstract long position();
public abstract boolean is64();
protected long readUI64() throws IOException {

View File

@@ -18,6 +18,11 @@ public class ByteArrayDataStream extends AbstractDataStream {
this(new byte[initialSize], use64bit);
}
@Override
public long position() {
return pos;
}
public ByteArrayDataStream(byte data[], boolean use64bit) {
this.data = data;
pos = 0;

View File

@@ -0,0 +1,77 @@
package com.jpexs.decompiler.flash.iggy;
import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType;
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
public class IggyDataReader implements StructureInterface {
@IggyFieldType(value = DataType.widechar_t, count = 48)
String name;
@IggyFieldType(value = DataType.uint64_t)
long unk_pad;
@IggyArrayFieldType(value = DataType.uint64_t, countField = "font_count")
long[] font_main_offsets;
@IggyArrayFieldType(value = DataType.uint64_t, countField = "font_count")
long font_info_offsets[];
private IggyFlashHeader64 header;
public IggyDataReader(IggyFlashHeader64 header, AbstractDataStream stream) throws IOException {
this.header = header;
readFromDataStream(stream);
}
@Override
public void readFromDataStream(AbstractDataStream stream) throws IOException {
stream.seek(header.swf_name_offset, SeekMode.SET);
StringBuilder nameBuilder = new StringBuilder();
int charCnt = 0;
do {
char c = (char) stream.readUI16();
charCnt++;
if (c == '\0') {
break;
}
nameBuilder.append(c);
} while (true);
stream.seek(48 - charCnt * 2, SeekMode.CUR);
name = nameBuilder.toString();
unk_pad = stream.readUI64(); //padding one
for (int i = 0; i < header.font_count; i++) {
font_main_offsets[i] = stream.readUI64();
}
for (int i = 0; i < header.font_count; i++) {
font_info_offsets[i] = stream.readUI64();
}
System.out.println("pos=" + stream.position());
}
public String getName() {
return name;
}
@Override
public void writeToDataStream(AbstractDataStream stream) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[\r\n");
sb.append("name ").append(name).append("\r\n");
sb.append("]");
return sb.toString();
}
}

View File

@@ -30,12 +30,17 @@ public class IggyFile extends AbstractDataStream implements AutoCloseable {
private IggyHeader header;
private List<IggySubFileEntry> subFileEntries = new ArrayList<>();
private List<List<Integer>> indexTables = new ArrayList<>();
private List<List<Long>> offsetTables = new ArrayList<>();
private List<IggyFlashHeaderInterface> headers = new ArrayList<>();
private List<IggyNameAndTagList> namesAndTagLists = new ArrayList<>();
private List<List<ByteArrayDataStream>> tagDataTables = new ArrayList<>();
private List<IggyDataReader> flashDataReaders = new ArrayList<>();
@Override
public long position() {
try {
return raf.getFilePointer();
} catch (IOException ex) {
return -1;
}
}
public IggyFile(File file) throws IOException {
raf = new RandomAccessFile(file, "r");
@@ -44,7 +49,9 @@ public class IggyFile extends AbstractDataStream implements AutoCloseable {
subFileEntries.add(new IggySubFileEntry(this));
}
List<ByteArrayDataStream> flashStreams = new ArrayList<>();
//TODO: use these two for something
List<List<Integer>> indexTables = new ArrayList<>();
List<List<Long>> offsetTables = new ArrayList<>();
for (int i = 0; i < subFileEntries.size(); i++) {
IggySubFileEntry entry = subFileEntries.get(i);
@@ -57,50 +64,19 @@ public class IggyFile extends AbstractDataStream implements AutoCloseable {
offsetTables.add(offsets);
} else if (entry.type == IggySubFileEntry.TYPE_FLASH) {
IggyFlashHeaderInterface hdr;
if (is64()) {
hdr = new IggyFlashHeader64(dataStream);
} else {
//if (is64()) {
//FIXME: Make 32 bit version work
hdr = new IggyFlashHeader64(dataStream);
/*} else {
hdr = new IggyFlashHeader32(dataStream);
}
//System.out.println("hdr=" + hdr);
IggyNameAndTagList nameTagList = new IggyNameAndTagList(dataStream);
//System.out.println("nameTagList=" + nameTagList);
}*/
System.out.println("hdr=" + hdr);
IggyDataReader dataReader = new IggyDataReader((IggyFlashHeader64) hdr, dataStream);
System.out.println("dataReader=" + dataReader);
headers.add(hdr);
namesAndTagLists.add(nameTagList);
flashStreams.add(dataStream);
flashDataReaders.add(dataReader);
}
}
for (int i = 0; i < flashStreams.size(); i++) {
ByteArrayDataStream flashStream = flashStreams.get(i);
List<Long> offsets = offsetTables.get(i);
List<Long> tagIds = namesAndTagLists.get(i).getTagIds();
List<Long> tagExtraInfo = namesAndTagLists.get(i).getTagIdsExtraInfo();
int offsetIndex = 3; //0 = SWF name, 1 = UI16 zero, 2 = tag list
List<ByteArrayDataStream> tagDataStreams = new ArrayList<>();
final int MAX_BUF_SIZE = 4096;
for (int t = 0; t < tagIds.size(); t++) {
long startOffset = offsets.get(offsetIndex);
long endOffset = offsets.get(offsetIndex + 1);
long dataLength = endOffset - startOffset;
long extraInfo = tagExtraInfo.get(t); //TODO: What's this for?
flashStream.seek(startOffset, SeekMode.SET);
long remLength = dataLength;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
do {
int readCount = remLength >= MAX_BUF_SIZE ? MAX_BUF_SIZE : (int) remLength;
byte[] buf = flashStream.readBytes(readCount);
baos.write(buf);
remLength -= readCount;
} while (remLength > 0);
byte tagBytes[] = baos.toByteArray(); //TODO: optimize speed - without ByteArrayOutputStream
ByteArrayDataStream tagDataStream = new ByteArrayDataStream(tagBytes, is64());
tagDataStreams.add(tagDataStream);
offsetIndex++;
}
tagDataTables.add(tagDataStreams);
}
}
@Override
@@ -689,27 +665,11 @@ public class IggyFile extends AbstractDataStream implements AutoCloseable {
}
public int getSwfCount() {
return tagDataTables.size();
return flashDataReaders.size();
}
public String getSwfName(int swfIndex) {
return namesAndTagLists.get(swfIndex).getName();
}
public List<Long> getSwfTagIds(int swfIndex) {
return namesAndTagLists.get(swfIndex).getTagIds();
}
public Long getSwfTagId(int swfIndex, int tagIndex) {
return namesAndTagLists.get(swfIndex).getTagIds().get(tagIndex);
}
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);
return flashDataReaders.get(swfIndex).getName();
}
public long getSwfXMin(int swfIndex) {
@@ -731,36 +691,4 @@ public class IggyFile extends AbstractDataStream implements AutoCloseable {
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

@@ -1,12 +1,7 @@
package com.jpexs.decompiler.flash.iggy;
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.TagTypeInfo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
*
@@ -17,7 +12,7 @@ import java.util.Map;
public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
@IggyFieldType(DataType.uint64_t)
long main_offset; // 0 Relative offset to first section (matches sizeof header);
long swf_name_offset; // 0 Relative offset to first section (matches sizeof header);
@IggyFieldType(DataType.uint64_t)
long as3_section_offset; // 8 Relative offset to as3 file names table...
@IggyFieldType(DataType.uint64_t)
@@ -48,15 +43,15 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
long unk_50;
@IggyFieldType(DataType.uint32_t)
long unk_54;
float frameRate;
float frame_rate;
@IggyFieldType(DataType.uint32_t)
long unk_5C;
@IggyFieldType(DataType.uint64_t)
long unk_60;
long fonts_offset;
@IggyFieldType(DataType.uint64_t)
long unk_68;
long font_infos_offset;
@IggyFieldType(DataType.uint64_t)
long names_offset; // 0x70 relative offset to the names/import section of the file
long names_offset; // 0x70 relative offset to the names/import section of the file - end of fonts
@IggyFieldType(DataType.uint64_t)
long unk_offset5; // 0x78 relative offset to something
@IggyFieldType(DataType.uint64_t)
@@ -71,12 +66,12 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
long as3_names_offset; // 0xA0 relative offset to as3 file names table (or classes names or whatever)
@IggyFieldType(DataType.uint32_t)
long unk_A8;
@IggyFieldType(DataType.uint32_t) //font_main_off
long unk_AC; //font_main_size
@IggyFieldType(DataType.uint32_t) //font_info_off
long font_count; // Maybe number of classes / as3 names //font_info_size
@IggyFieldType(DataType.uint32_t)
long unk_AC;
@IggyFieldType(DataType.uint32_t)
long unk_B0; // Maybe number of classes / as3 names
@IggyFieldType(DataType.uint32_t)
long unk_B4;
long unk_B4; //zero (?)
// Offset 0xB8 (outside header): there are *unk_40* relative offsets that point to flash objects.
// The flash objects are in a format different to swf but there is probably a way to convert between them.
@@ -88,18 +83,9 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
readFromDataStream(stream);
}
/*
offsets:
name (UI16 chars, zero terminated)
UI16
taglist_offset (aka main_offset)
after_taglist
*/
@Override
public void readFromDataStream(AbstractDataStream stream) throws IOException {
main_offset = stream.readUI64();
swf_name_offset = stream.readUI64();
as3_section_offset = stream.readUI64();
unk_offset = stream.readUI64();
unk_offset2 = stream.readUI64();
@@ -115,10 +101,10 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
unk_4C = stream.readUI32();
unk_50 = stream.readUI32();
unk_54 = stream.readUI32();
frameRate = stream.readFloat();
frame_rate = stream.readFloat();
unk_5C = stream.readUI32();
unk_60 = stream.readUI64();
unk_68 = stream.readUI64();
fonts_offset = stream.readUI64();
font_infos_offset = stream.readUI64();
names_offset = stream.readUI64();
unk_offset5 = stream.readUI64();
unk_80 = stream.readUI64();
@@ -128,8 +114,9 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
as3_names_offset = stream.readUI64();
unk_A8 = stream.readUI32();
unk_AC = stream.readUI32();
unk_B0 = stream.readUI32();
font_count = stream.readUI32();
unk_B4 = stream.readUI32();
}
@Override
@@ -141,28 +128,28 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[\r\n");
sb.append("main_offset ").append(main_offset).append("\r\n");
sb.append("main_offset ").append(swf_name_offset).append("\r\n");
sb.append("as3_section_offset ").append(as3_section_offset);
sb.append(" global: ").append(main_offset + as3_section_offset);
sb.append(" global: ").append(swf_name_offset + as3_section_offset);
sb.append("\r\n");
sb.append("unk_offset ").append(unk_offset);
if (unk_offset != 1) {
sb.append(" global: ").append(main_offset + unk_offset);
sb.append(" global: ").append(swf_name_offset + unk_offset);
}
sb.append("\r\n");
sb.append("unk_offset2 ").append(unk_offset2);
if (unk_offset2 != 1) {
sb.append(" global: ").append(main_offset + unk_offset2);
sb.append(" global: ").append(swf_name_offset + unk_offset2);
}
sb.append("\r\n");
sb.append("unk_offset3 ").append(unk_offset3);
if (unk_offset3 != 1) {
sb.append(" global: ").append(main_offset + unk_offset3);
sb.append(" global: ").append(swf_name_offset + unk_offset3);
}
sb.append("\r\n");
sb.append("unk_offset4 ").append(unk_offset4);
if (unk_offset4 != 1) {
sb.append(" global: ").append(main_offset + unk_offset4);
sb.append(" global: ").append(swf_name_offset + unk_offset4);
}
sb.append("\r\n");
sb.append("xmin ").append(xmin).append("\r\n");
@@ -175,10 +162,10 @@ 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("frameRate ").append(frameRate).append("\r\n");
sb.append("frame_rate ").append(frame_rate).append("\r\n");
sb.append("unk_5C ").append(unk_5C).append("\r\n");
sb.append("unk_60 ").append(unk_60).append("\r\n");
sb.append("unk_68 ").append(unk_68).append("\r\n");
sb.append("fonts_offset ").append(fonts_offset).append("\r\n");
sb.append("font_infos_offset ").append(font_infos_offset).append("\r\n");
sb.append("names_offset ").append(names_offset).append("\r\n");
sb.append("unk_offset5 ").append(unk_offset5).append("\r\n");
sb.append("unk_80 ").append(unk_80).append("\r\n");
@@ -188,7 +175,7 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
sb.append("as3_names_offset ").append(as3_names_offset).append("\r\n");
sb.append("unk_A8 ").append(unk_A8).append("\r\n");
sb.append("unk_AC ").append(unk_AC).append("\r\n");
sb.append("unk_B0 ").append(unk_B0).append("\r\n");
sb.append("font_count ").append(font_count).append("\r\n");
sb.append("unk_B4 ").append(unk_B4).append("\r\n");
sb.append("]");
return sb.toString();
@@ -217,7 +204,7 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
@Override
public float getFrameRate() {
return frameRate;
return frame_rate;
}
}

View File

@@ -1,89 +0,0 @@
package com.jpexs.decompiler.flash.iggy;
import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType;
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
public class IggyNameAndTagList implements StructureInterface {
@IggyFieldType(value = DataType.widechar_t)
private String name;
@IggyArrayFieldType(value = DataType.ubits, count = 10)
private List<Long> tagIds;
@IggyArrayFieldType(value = DataType.uint16_t)
private List<Long> tagIdsExtraInfo;
public IggyNameAndTagList(String name, List<Long> tagIds, List<Long> tagIdsExtendedInfo) {
this.name = name;
this.tagIds = tagIds;
this.tagIdsExtraInfo = tagIdsExtendedInfo;
}
public IggyNameAndTagList(AbstractDataStream stream) throws IOException {
readFromDataStream(stream);
}
@Override
public void readFromDataStream(AbstractDataStream stream) throws IOException {
StringBuilder nameBuilder = new StringBuilder();
do {
char c = (char) stream.readUI16();
if (c == '\0') {
break;
}
nameBuilder.append(c);
} while (true);
name = nameBuilder.toString();
tagIds = new ArrayList<>();
tagIdsExtraInfo = new ArrayList<>();
while (true) {
long tagType = stream.readUI32() & 0xffffffffL;
if (tagType == 0) {
break;
}
long tagLength = stream.readUI32();
tagIds.add(tagType);
tagIdsExtraInfo.add(tagLength);
}
}
public String getName() {
return name;
}
public List<Long> getTagIds() {
return tagIds;
}
public List<Long> getTagIdsExtraInfo() {
return tagIdsExtraInfo;
}
@Override
public void writeToDataStream(AbstractDataStream stream) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[\r\n");
sb.append("name ").append(name).append("\r\n");
sb.append("tags:").append("\r\n");
for (int i = 0; i < tagIds.size(); i++) {
sb.append("tag ").append(String.format("%08X", tagIds.get(i))).append(" extra ").append(tagIdsExtraInfo.get(i)).append("\r\n");
}
sb.append("]");
return sb.toString();
}
}

View File

@@ -2,17 +2,8 @@ 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.AbstractDataStream;
import com.jpexs.decompiler.flash.iggy.IggyFile;
import com.jpexs.decompiler.flash.iggy.IggyFlashHeaderInterface;
import com.jpexs.decompiler.flash.iggy.SeekMode;
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.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -20,7 +11,7 @@ import java.io.OutputStream;
/**
*
* Unfinished WIP!
* WIP
*
* @author JPEXS
*/
@@ -70,7 +61,7 @@ public class IggyToSwfConvertor {
(int) (file.getSwfYMax(swfIndex) * SWF.unitDivisor));
swf.version = 9; //FIXME
//TODO: Convert tags
//TODO!!!
throw new UnsupportedOperationException("Not implemented yet");
}
}