mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-27 05:30:47 +00:00
Multi thread AS search
This commit is contained in:
@@ -1,244 +1,243 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.streams.DataStreamInterface;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.RandomAccessFileDataStream;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.SeekMode;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.StructureInterface;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.TemporaryDataStream;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*
|
||||
* Based of works of somebody called eternity.
|
||||
*
|
||||
*/
|
||||
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 IggySwf iggySwf;
|
||||
|
||||
public static final int FIRST_TAG_POSITION = 3;
|
||||
|
||||
public IggySwf getSwf() {
|
||||
return iggySwf;
|
||||
}
|
||||
|
||||
public IggyFile(String filePath) throws IOException {
|
||||
this(new File(filePath));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public IggySubFileEntry getSubFileEntry(int entryIndex) {
|
||||
if (entryIndex < 0 || entryIndex >= subFileEntries.size()) {
|
||||
throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists");
|
||||
}
|
||||
return subFileEntries.get(entryIndex);
|
||||
}
|
||||
|
||||
public int getNumEntries() {
|
||||
return subFileEntries.size();
|
||||
}
|
||||
|
||||
public byte[] getEntryData(int entryIndex) {
|
||||
if (entryIndex < 0 || entryIndex >= subFileEntries.size()) {
|
||||
throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists");
|
||||
}
|
||||
return subFileEntriesData.get(entryIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[IggyFile:").append("\r\n");
|
||||
sb.append(header).append("\r\n");
|
||||
sb.append("Entries:").append("\r\n");
|
||||
for (IggySubFileEntry entry : subFileEntries) {
|
||||
sb.append(entry).append("\r\n");
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void extractIggyFile(File iggyFile, File extractDir) throws IOException {
|
||||
final String FILENAME_FORMAT = "index%d_type%d.bin";
|
||||
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)))) {
|
||||
fos.write(ir.getEntryData(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getSwfName() {
|
||||
return iggySwf.getName();
|
||||
}
|
||||
|
||||
public long getSwfXMin() {
|
||||
return iggySwf.getHdr().getXMin();
|
||||
}
|
||||
|
||||
public long getSwfYMin() {
|
||||
return iggySwf.getHdr().getYMin();
|
||||
}
|
||||
|
||||
public long getSwfXMax() {
|
||||
return iggySwf.getHdr().getXMax();
|
||||
}
|
||||
|
||||
public long getSwfYMax() {
|
||||
return iggySwf.getHdr().getYMax();
|
||||
}
|
||||
|
||||
public float getSwfFrameRate() {
|
||||
return iggySwf.getHdr().getFrameRate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes entries of type INDEX.There can be more than one INDEX,
|
||||
* continuous. This removes all ot them.
|
||||
*/
|
||||
public void removeIndexEntries() {
|
||||
long offsetsChange = 0;
|
||||
final int ENTRY_SIZE = 16;
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
IggySubFileEntry entry = subFileEntries.get(i);
|
||||
entry.offset += offsetsChange;
|
||||
if (entry.type == IggySubFileEntry.TYPE_INDEX) {
|
||||
offsetsChange = offsetsChange - entry.size - ENTRY_SIZE;
|
||||
subFileEntriesData.remove(i);
|
||||
subFileEntries.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean updateFlashEntry() throws IOException {
|
||||
|
||||
byte replacementData[];
|
||||
byte replacementIndexData[];
|
||||
IggyIndexBuilder ib = new IggyIndexBuilder();
|
||||
try (DataStreamInterface stream = new TemporaryDataStream()) {
|
||||
stream.setIndexing(ib);
|
||||
iggySwf.writeToDataStream(stream);
|
||||
replacementData = stream.getAllBytes();
|
||||
replacementIndexData = ib.getIndexBytes();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(IggyFile.class.getName()).log(Level.SEVERE, "Error during updating SWF", ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
removeIndexEntries();
|
||||
IggySubFileEntry indexEntry = new IggySubFileEntry(IggySubFileEntry.TYPE_INDEX, replacementIndexData.length, replacementIndexData.length, 0 /*offset will be set automatically*/);
|
||||
subFileEntries.add(indexEntry);
|
||||
subFileEntriesData.add(replacementIndexData);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseEntries() throws IOException {
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
IggySubFileEntry entry = subFileEntries.get(i);
|
||||
if (entry.type == IggySubFileEntry.TYPE_FLASH) {
|
||||
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<>());
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(ReadDataStreamInterface stream) throws IOException {
|
||||
header = new IggyHeader(stream);
|
||||
if (!header.is64()) {
|
||||
throw new IOException("32 bit iggy files are not (yet) supported, sorry");
|
||||
}
|
||||
for (int i = 0; i < header.getNumSubfiles(); i++) {
|
||||
subFileEntries.add(new IggySubFileEntry(stream));
|
||||
}
|
||||
for (IggySubFileEntry entry : subFileEntries) {
|
||||
stream.seek(entry.offset, SeekMode.SET);
|
||||
byte[] entryData = stream.readBytes((int) entry.size);
|
||||
subFileEntriesData.add(entryData);
|
||||
}
|
||||
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);
|
||||
|
||||
long startOffset = IggyHeader.STRUCT_SIZE + IggySubFileEntry.STRUCTURE_SIZE * subFileEntries.size();
|
||||
long currentOffset = startOffset;
|
||||
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
IggySubFileEntry entry = subFileEntries.get(i);
|
||||
entry.offset = currentOffset;
|
||||
currentOffset += entry.size;
|
||||
entry.writeToDataStream(stream);
|
||||
}
|
||||
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
byte[] entryData = subFileEntriesData.get(i);
|
||||
stream.writeBytes(entryData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.streams.DataStreamInterface;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.RandomAccessFileDataStream;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.SeekMode;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.StructureInterface;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.TemporaryDataStream;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*
|
||||
* Based of works of somebody called eternity.
|
||||
*
|
||||
*/
|
||||
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 IggySwf iggySwf;
|
||||
|
||||
public static final int FIRST_TAG_POSITION = 3;
|
||||
|
||||
public IggySwf getSwf() {
|
||||
return iggySwf;
|
||||
}
|
||||
|
||||
public IggyFile(String filePath) throws IOException {
|
||||
this(new File(filePath));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public IggySubFileEntry getSubFileEntry(int entryIndex) {
|
||||
if (entryIndex < 0 || entryIndex >= subFileEntries.size()) {
|
||||
throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists");
|
||||
}
|
||||
return subFileEntries.get(entryIndex);
|
||||
}
|
||||
|
||||
public int getNumEntries() {
|
||||
return subFileEntries.size();
|
||||
}
|
||||
|
||||
public byte[] getEntryData(int entryIndex) {
|
||||
if (entryIndex < 0 || entryIndex >= subFileEntries.size()) {
|
||||
throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists");
|
||||
}
|
||||
return subFileEntriesData.get(entryIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[IggyFile:").append("\r\n");
|
||||
sb.append(header).append("\r\n");
|
||||
sb.append("Entries:").append("\r\n");
|
||||
for (IggySubFileEntry entry : subFileEntries) {
|
||||
sb.append(entry).append("\r\n");
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void extractIggyFile(File iggyFile, File extractDir) throws IOException {
|
||||
final String FILENAME_FORMAT = "index%d_type%d.bin";
|
||||
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)))) {
|
||||
fos.write(ir.getEntryData(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getSwfName() {
|
||||
return iggySwf.getName();
|
||||
}
|
||||
|
||||
public long getSwfXMin() {
|
||||
return iggySwf.getHdr().getXMin();
|
||||
}
|
||||
|
||||
public long getSwfYMin() {
|
||||
return iggySwf.getHdr().getYMin();
|
||||
}
|
||||
|
||||
public long getSwfXMax() {
|
||||
return iggySwf.getHdr().getXMax();
|
||||
}
|
||||
|
||||
public long getSwfYMax() {
|
||||
return iggySwf.getHdr().getYMax();
|
||||
}
|
||||
|
||||
public float getSwfFrameRate() {
|
||||
return iggySwf.getHdr().getFrameRate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes entries of type INDEX.There can be more than one INDEX,
|
||||
* continuous. This removes all ot them.
|
||||
*/
|
||||
public void removeIndexEntries() {
|
||||
long offsetsChange = 0;
|
||||
final int ENTRY_SIZE = 16;
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
IggySubFileEntry entry = subFileEntries.get(i);
|
||||
entry.offset += offsetsChange;
|
||||
if (entry.type == IggySubFileEntry.TYPE_INDEX) {
|
||||
offsetsChange = offsetsChange - entry.size - ENTRY_SIZE;
|
||||
subFileEntriesData.remove(i);
|
||||
subFileEntries.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean updateFlashEntry() throws IOException {
|
||||
|
||||
byte replacementData[];
|
||||
byte replacementIndexData[];
|
||||
IggyIndexBuilder ib = new IggyIndexBuilder();
|
||||
try (DataStreamInterface stream = new TemporaryDataStream()) {
|
||||
stream.setIndexing(ib);
|
||||
iggySwf.writeToDataStream(stream);
|
||||
replacementData = stream.getAllBytes();
|
||||
replacementIndexData = ib.getIndexBytes();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(IggyFile.class.getName()).log(Level.SEVERE, "Error during updating SWF", ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
removeIndexEntries();
|
||||
IggySubFileEntry indexEntry = new IggySubFileEntry(IggySubFileEntry.TYPE_INDEX, replacementIndexData.length, replacementIndexData.length, 0 /*offset will be set automatically*/);
|
||||
subFileEntries.add(indexEntry);
|
||||
subFileEntriesData.add(replacementIndexData);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseEntries() throws IOException {
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
IggySubFileEntry entry = subFileEntries.get(i);
|
||||
if (entry.type == IggySubFileEntry.TYPE_FLASH) {
|
||||
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<>());
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(ReadDataStreamInterface stream) throws IOException {
|
||||
header = new IggyHeader(stream);
|
||||
if (!header.is64()) {
|
||||
throw new IOException("32 bit iggy files are not (yet) supported, sorry");
|
||||
}
|
||||
for (int i = 0; i < header.getNumSubfiles(); i++) {
|
||||
subFileEntries.add(new IggySubFileEntry(stream));
|
||||
}
|
||||
for (IggySubFileEntry entry : subFileEntries) {
|
||||
stream.seek(entry.offset, SeekMode.SET);
|
||||
byte[] entryData = stream.readBytes((int) entry.size);
|
||||
subFileEntriesData.add(entryData);
|
||||
}
|
||||
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);
|
||||
|
||||
long startOffset = IggyHeader.STRUCT_SIZE + IggySubFileEntry.STRUCTURE_SIZE * subFileEntries.size();
|
||||
long currentOffset = startOffset;
|
||||
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
IggySubFileEntry entry = subFileEntries.get(i);
|
||||
entry.offset = currentOffset;
|
||||
currentOffset += entry.size;
|
||||
entry.writeToDataStream(stream);
|
||||
}
|
||||
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
byte[] entryData = subFileEntriesData.get(i);
|
||||
stream.writeBytes(entryData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,64 +18,94 @@ public class IggyFlashHeader32 implements IggyFlashHeaderInterface {
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long main_offset; // 0 Relative offset to first section (matches sizeof header)
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long as3_section_offset; // 4 Relative offset to as3 file names table...
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_offset; // 8 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_offset2; // 0xC relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_offset3; // 0x10 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_offset4; // 0x14 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long xmin; //0x18 in pixels
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long ymin; //0x0C in pixels
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long xmax; // 0x20 in pixels
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long ymax; // 0x24 in pixels
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_28; // probably number of blocks/objects after header
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_2C;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_30;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_34;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_38;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_3C;
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float frameRate;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_44;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_48;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_4C;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long names_offset; // 0x50 relative offset to the names/import section of the file
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_offset5; // 0x54 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long unk_58; // Maybe number of imports/names pointed by names_offset
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long last_section_offset; // 0x60 relative offset, points to the small last section of the file
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_offset6; // 0x64 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long as3_code_offset; // 0x68 relative offset to as3 code (8 bytes header + abc blob)
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long as3_names_offset; // 0x6C relative offset to as3 file names table (or classes names or whatever)
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_70;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_74;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_78; // Maybe number of classes / as3 names
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_7C;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jindra
|
||||
* @author JPEXS
|
||||
*
|
||||
* Based of works of somebody called eternity.
|
||||
*/
|
||||
@@ -17,62 +17,91 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_base; // 0 Relative offset to first section (matches sizeof header);
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_sequence_end; // 8 Relative offset to as3 file names table...
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_font_end; // 0x10 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_sequence_start1; // 0x18 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_sequence_start2; // 0x20 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_sequence_start3; // 0x28 names_offset; 0x50 relative pointer to the names/import section of the file
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long xmin; // 0x30 in pixels
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long ymin; // 0x34 in pixels
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long xmax; // 0x38 in pixels
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long ymax; // 0x3C in pixels
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_40; // probably numer of blocks/objects after header
|
||||
long unk_40; // probably number of blocks/objects after header
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_44;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_48;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_4C;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_50;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_54;
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float frame_rate;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long unk_5C;
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long imported_guid;
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long my_guid; // same for some fonts (eng + chinese)
|
||||
|
||||
@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_unk78; // 0x78 relative offset to something
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long unk80;
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_last_section;
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_flash_filename;
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_decl_strings;
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long off_type_of_fonts;
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long flags;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long font_count;
|
||||
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long zero2;
|
||||
|
||||
@@ -87,29 +116,51 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
|
||||
}
|
||||
|
||||
private long base_address;
|
||||
|
||||
private long sequence_end_address;
|
||||
|
||||
private long font_end_address;
|
||||
|
||||
private long sequence_start_address1;
|
||||
|
||||
private long sequence_start_address2;
|
||||
|
||||
private long sequence_start_address3;
|
||||
|
||||
private long names_address;
|
||||
|
||||
private long unk78_address;
|
||||
|
||||
private long last_section_address;
|
||||
|
||||
private long flash_filename_address;
|
||||
|
||||
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() {
|
||||
@@ -389,5 +440,4 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
|
||||
public float getFrameRate() {
|
||||
return frame_rate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,24 +16,34 @@ public class IggyFontBinInfo implements StructureInterface {
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long size_of_this_info = STRUCT_SIZE;
|
||||
|
||||
@IggyFieldType(value = DataType.uint16_t, count = 4)
|
||||
int font_specific[];
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float normX;
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float zero;
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float zero2;
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float normY;
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float minSize;
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float maxSize;
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long order_in_iggy_file;
|
||||
|
||||
@IggyFieldType(DataType.int64_t)
|
||||
long address_back; //relative
|
||||
|
||||
@IggyFieldType(value = DataType.uint8_t, count = 40)
|
||||
byte pad[];
|
||||
|
||||
@@ -59,7 +69,7 @@ public class IggyFontBinInfo implements StructureInterface {
|
||||
maxSize = s.readFloat();
|
||||
order_in_iggy_file = s.readUI64();
|
||||
address_back = s.readSI64();
|
||||
//if(address_back + s.position() - 8 != text_offsets[i]) Printf("Wrong iggy font format (bininfo-offsetback) (%u)!\n",i);
|
||||
//if(address_back + s.position() - 8 != text_offsets[i]) Printf("Wrong iggy font format (bininfo-offsetback) (%u)!\n",i);
|
||||
pad = s.readBytes(40);
|
||||
}
|
||||
|
||||
@@ -79,5 +89,4 @@ public class IggyFontBinInfo implements StructureInterface {
|
||||
s.writeSI64(address_back);
|
||||
s.writeBytes(pad);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,339 +1,346 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
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.SeekMode;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.StructureInterface;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggySwf implements StructureInterface {
|
||||
|
||||
final static int NO_OFFSET = 1;
|
||||
|
||||
@IggyFieldType(value = DataType.wchar_t, count = 48)
|
||||
String name;
|
||||
|
||||
private List<IggyFont> fonts = new ArrayList<>();
|
||||
// private List<Long> font_data_addresses = new ArrayList<>();
|
||||
private List<IggyFont> add_fonts = new ArrayList<>();
|
||||
// private List<Long> add_font_data_addresses = new ArrayList<>();
|
||||
|
||||
private IggyFlashHeader64 hdr;
|
||||
|
||||
public IggySwf(ReadDataStreamInterface stream) throws IOException {
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
private List<IggyText> texts = 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 byte font_add_data[];
|
||||
//private List<Long> font_additional_size = new ArrayList<>();
|
||||
private IggyFontBinInfo font_bin_info[];
|
||||
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;
|
||||
private long ofs_additional;
|
||||
private long additional_address;
|
||||
|
||||
public IggyFlashHeader64 getHdr() {
|
||||
return hdr;
|
||||
}
|
||||
|
||||
public List<IggyFont> getFonts() {
|
||||
return fonts;
|
||||
}
|
||||
|
||||
public List<IggyFont> getAddFonts() {
|
||||
return add_fonts;
|
||||
}
|
||||
|
||||
public List<IggyText> getTexts() {
|
||||
return texts;
|
||||
}
|
||||
|
||||
public List<IggyText> getAddTexts() {
|
||||
return add_texts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(ReadDataStreamInterface s) throws IOException {
|
||||
this.hdr = new IggyFlashHeader64(s);
|
||||
//Save all font bytes to buffer for later easy modification
|
||||
//here is offset[0] - 184
|
||||
name = s.readWChar();
|
||||
//here is offset[1] - 230
|
||||
int pad8 = 8 - (int) (s.position() % 8);
|
||||
if (pad8 > 8) {
|
||||
s.seek(pad8, SeekMode.CUR);
|
||||
}
|
||||
//here is offset [2] - 232
|
||||
s.seek(hdr.getBaseAddress(), SeekMode.SET);
|
||||
s.readUI64(); //pad 1
|
||||
|
||||
List<Long> itemsAddresses = new ArrayList<>();
|
||||
|
||||
while (true) {
|
||||
long offset = s.readUI64();
|
||||
if (offset == 1) {
|
||||
break;
|
||||
}
|
||||
itemsAddresses.add(offset + s.position() - 8);
|
||||
}
|
||||
if (hdr.getImported_guid() != 0) {
|
||||
ofs_additional = s.readUI64();
|
||||
additional_address = ofs_additional == 1 ? 0 : ofs_additional + s.position() - 8;
|
||||
}
|
||||
for (Long addr : itemsAddresses) {
|
||||
s.seek(addr, SeekMode.SET);
|
||||
int kind = s.readUI8();
|
||||
s.seek(-1, SeekMode.CUR);
|
||||
switch (kind) {
|
||||
case 22 /*FONT*/:
|
||||
IggyFont font = new IggyFont(s);
|
||||
//font_data_addresses.add(addr);
|
||||
fonts.add(font);
|
||||
break;
|
||||
case 6 /*TEXT*/:
|
||||
IggyText text = new IggyText(s);
|
||||
//text_data_addresses.add(addr);
|
||||
texts.add(text);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unknown item kind: " + kind);
|
||||
}
|
||||
}
|
||||
|
||||
if (additional_address != 0) {
|
||||
s.seek(additional_address, SeekMode.SET);
|
||||
List<Long> additionalItemsAddresses = new ArrayList<>();
|
||||
while (true) {
|
||||
long offset = s.readUI64();
|
||||
if (offset == 1) {
|
||||
break;
|
||||
}
|
||||
additionalItemsAddresses.add(offset + s.position() - 8);
|
||||
}
|
||||
for (Long addr : additionalItemsAddresses) {
|
||||
s.seek(addr, SeekMode.SET);
|
||||
int kind = s.readUI8();
|
||||
s.seek(-1, SeekMode.CUR);
|
||||
switch (kind) {
|
||||
case 22 /*FONT*/:
|
||||
IggyFont font = new IggyFont(s);
|
||||
//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_texts.add(text);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unknown imported item kind: " + kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
s.seek(hdr.getFontEndAddress(), SeekMode.SET);
|
||||
//here is offset [4] - 856 ?
|
||||
font_bin_info = new IggyFontBinInfo[(int) hdr.font_count];
|
||||
for (int i = 0; i < hdr.font_count; i++) {
|
||||
font_bin_info[i] = new IggyFontBinInfo(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];
|
||||
for (int i = 0; i < hdr.font_count; i++) {
|
||||
type_info[i] = new IggyFontTypeInfo(s);
|
||||
}
|
||||
for (int i = 0; i < hdr.font_count; i++) {
|
||||
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);
|
||||
decl_strings = new IggyDeclStrings(s);
|
||||
/*WriteDataStreamInterface outs = new TemporaryDataStream();
|
||||
writeToDataStream(outs);
|
||||
Helper.writeFile("d:\\Dropbox\\jpexs-laptop\\iggi\\parts\\swf_out.bin", outs.getAllBytes());*/
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(WriteDataStreamInterface s) throws IOException {
|
||||
IggyIndexBuilder ib = s.getIndexing();
|
||||
hdr.writeToDataStream(s);
|
||||
s.writeWChar(name);
|
||||
s.pad8bytes();
|
||||
s.writeUI64(1);
|
||||
ib.write16bitArray(name.length() + 1);
|
||||
ib.writeTwoPaddingBytes();
|
||||
ib.write64bitPointerArray(64);
|
||||
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);
|
||||
}
|
||||
List<Long> textPosFillLater = new ArrayList<>();
|
||||
for (int i = 0; i < texts.size(); i++) {
|
||||
textPosFillLater.add(s.position());
|
||||
s.writeUI64(FILL_LATER);
|
||||
}
|
||||
s.writeUI64(1);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for (int i = 0; i < fonts.size(); i++) {
|
||||
s.setOlderOffsetToThisPos(fontPosFillLater.get(i));
|
||||
fonts.get(i).writeToDataStream(s);
|
||||
}
|
||||
for (int i = 0; i < texts.size(); i++) {
|
||||
s.setOlderOffsetToThisPos(textPosFillLater.get(i));
|
||||
texts.get(i).writeToDataStream(s);
|
||||
}
|
||||
|
||||
if (!add_fonts.isEmpty() || !add_texts.isEmpty()) {
|
||||
s.setOlderOffsetToThisPos(addPosFillLater);
|
||||
|
||||
List<Long> addFontPosFillLater = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < add_fonts.size(); i++) {
|
||||
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.setOlderOffsetToThisPos(addTextPosFillLater.get(i));
|
||||
add_texts.get(i).writeToDataStream(s);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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.setOlderOffsetToThisPos(hdr.getSequence_end_ofs_pos());
|
||||
s.pad8bytes();
|
||||
ib.pad8bytes();
|
||||
|
||||
ib.writeConstLengthArray(IggyIndexBuilder.CONST_TYPE_INFO_SIZE, hdr.font_count);
|
||||
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);
|
||||
s.setOlderOffsetToThisPos(type_info[i].getLocal_name_ofs_pos());
|
||||
s.writeWChar(type_info_name[i]);
|
||||
}
|
||||
s.pad8bytes();
|
||||
ib.pad8bytes();
|
||||
|
||||
s.setOlderOffsetToThisPos(hdr.getDecl_strings_ofs_pos());
|
||||
//s.seek(hdr.getDeclStringsAddress(), SeekMode.SET);
|
||||
decl_strings.writeToDataStream(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[\r\n");
|
||||
sb.append("name ").append(name).append("\r\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public IggyDeclStrings getDeclStrings() {
|
||||
return decl_strings;
|
||||
}
|
||||
|
||||
}
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
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.SeekMode;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.StructureInterface;
|
||||
import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggySwf implements StructureInterface {
|
||||
|
||||
final static int NO_OFFSET = 1;
|
||||
|
||||
@IggyFieldType(value = DataType.wchar_t, count = 48)
|
||||
String name;
|
||||
|
||||
private List<IggyFont> fonts = new ArrayList<>();
|
||||
|
||||
// private List<Long> font_data_addresses = new ArrayList<>();
|
||||
private List<IggyFont> add_fonts = new ArrayList<>();
|
||||
// private List<Long> add_font_data_addresses = new ArrayList<>();
|
||||
|
||||
private IggyFlashHeader64 hdr;
|
||||
|
||||
public IggySwf(ReadDataStreamInterface stream) throws IOException {
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
private List<IggyText> texts = 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 byte font_add_data[];
|
||||
//private List<Long> font_additional_size = new ArrayList<>();
|
||||
private IggyFontBinInfo font_bin_info[];
|
||||
|
||||
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;
|
||||
|
||||
private long ofs_additional;
|
||||
|
||||
private long additional_address;
|
||||
|
||||
public IggyFlashHeader64 getHdr() {
|
||||
return hdr;
|
||||
}
|
||||
|
||||
public List<IggyFont> getFonts() {
|
||||
return fonts;
|
||||
}
|
||||
|
||||
public List<IggyFont> getAddFonts() {
|
||||
return add_fonts;
|
||||
}
|
||||
|
||||
public List<IggyText> getTexts() {
|
||||
return texts;
|
||||
}
|
||||
|
||||
public List<IggyText> getAddTexts() {
|
||||
return add_texts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(ReadDataStreamInterface s) throws IOException {
|
||||
this.hdr = new IggyFlashHeader64(s);
|
||||
//Save all font bytes to buffer for later easy modification
|
||||
//here is offset[0] - 184
|
||||
name = s.readWChar();
|
||||
//here is offset[1] - 230
|
||||
int pad8 = 8 - (int) (s.position() % 8);
|
||||
if (pad8 > 8) {
|
||||
s.seek(pad8, SeekMode.CUR);
|
||||
}
|
||||
//here is offset [2] - 232
|
||||
s.seek(hdr.getBaseAddress(), SeekMode.SET);
|
||||
s.readUI64(); //pad 1
|
||||
|
||||
List<Long> itemsAddresses = new ArrayList<>();
|
||||
|
||||
while (true) {
|
||||
long offset = s.readUI64();
|
||||
if (offset == 1) {
|
||||
break;
|
||||
}
|
||||
itemsAddresses.add(offset + s.position() - 8);
|
||||
}
|
||||
if (hdr.getImported_guid() != 0) {
|
||||
ofs_additional = s.readUI64();
|
||||
additional_address = ofs_additional == 1 ? 0 : ofs_additional + s.position() - 8;
|
||||
}
|
||||
for (Long addr : itemsAddresses) {
|
||||
s.seek(addr, SeekMode.SET);
|
||||
int kind = s.readUI8();
|
||||
s.seek(-1, SeekMode.CUR);
|
||||
switch (kind) {
|
||||
case 22 /*FONT*/:
|
||||
IggyFont font = new IggyFont(s);
|
||||
//font_data_addresses.add(addr);
|
||||
fonts.add(font);
|
||||
break;
|
||||
case 6 /*TEXT*/:
|
||||
IggyText text = new IggyText(s);
|
||||
//text_data_addresses.add(addr);
|
||||
texts.add(text);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unknown item kind: " + kind);
|
||||
}
|
||||
}
|
||||
|
||||
if (additional_address != 0) {
|
||||
s.seek(additional_address, SeekMode.SET);
|
||||
List<Long> additionalItemsAddresses = new ArrayList<>();
|
||||
while (true) {
|
||||
long offset = s.readUI64();
|
||||
if (offset == 1) {
|
||||
break;
|
||||
}
|
||||
additionalItemsAddresses.add(offset + s.position() - 8);
|
||||
}
|
||||
for (Long addr : additionalItemsAddresses) {
|
||||
s.seek(addr, SeekMode.SET);
|
||||
int kind = s.readUI8();
|
||||
s.seek(-1, SeekMode.CUR);
|
||||
switch (kind) {
|
||||
case 22 /*FONT*/:
|
||||
IggyFont font = new IggyFont(s);
|
||||
//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_texts.add(text);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unknown imported item kind: " + kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
s.seek(hdr.getFontEndAddress(), SeekMode.SET);
|
||||
//here is offset [4] - 856 ?
|
||||
font_bin_info = new IggyFontBinInfo[(int) hdr.font_count];
|
||||
for (int i = 0; i < hdr.font_count; i++) {
|
||||
font_bin_info[i] = new IggyFontBinInfo(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];
|
||||
for (int i = 0; i < hdr.font_count; i++) {
|
||||
type_info[i] = new IggyFontTypeInfo(s);
|
||||
}
|
||||
for (int i = 0; i < hdr.font_count; i++) {
|
||||
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);
|
||||
decl_strings = new IggyDeclStrings(s);
|
||||
/*WriteDataStreamInterface outs = new TemporaryDataStream();
|
||||
writeToDataStream(outs);
|
||||
Helper.writeFile("d:\\Dropbox\\jpexs-laptop\\iggi\\parts\\swf_out.bin", outs.getAllBytes());*/
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(WriteDataStreamInterface s) throws IOException {
|
||||
IggyIndexBuilder ib = s.getIndexing();
|
||||
hdr.writeToDataStream(s);
|
||||
s.writeWChar(name);
|
||||
s.pad8bytes();
|
||||
s.writeUI64(1);
|
||||
ib.write16bitArray(name.length() + 1);
|
||||
ib.writeTwoPaddingBytes();
|
||||
ib.write64bitPointerArray(64);
|
||||
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);
|
||||
}
|
||||
List<Long> textPosFillLater = new ArrayList<>();
|
||||
for (int i = 0; i < texts.size(); i++) {
|
||||
textPosFillLater.add(s.position());
|
||||
s.writeUI64(FILL_LATER);
|
||||
}
|
||||
s.writeUI64(1);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for (int i = 0; i < fonts.size(); i++) {
|
||||
s.setOlderOffsetToThisPos(fontPosFillLater.get(i));
|
||||
fonts.get(i).writeToDataStream(s);
|
||||
}
|
||||
for (int i = 0; i < texts.size(); i++) {
|
||||
s.setOlderOffsetToThisPos(textPosFillLater.get(i));
|
||||
texts.get(i).writeToDataStream(s);
|
||||
}
|
||||
|
||||
if (!add_fonts.isEmpty() || !add_texts.isEmpty()) {
|
||||
s.setOlderOffsetToThisPos(addPosFillLater);
|
||||
|
||||
List<Long> addFontPosFillLater = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < add_fonts.size(); i++) {
|
||||
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.setOlderOffsetToThisPos(addTextPosFillLater.get(i));
|
||||
add_texts.get(i).writeToDataStream(s);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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.setOlderOffsetToThisPos(hdr.getSequence_end_ofs_pos());
|
||||
s.pad8bytes();
|
||||
ib.pad8bytes();
|
||||
|
||||
ib.writeConstLengthArray(IggyIndexBuilder.CONST_TYPE_INFO_SIZE, hdr.font_count);
|
||||
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);
|
||||
s.setOlderOffsetToThisPos(type_info[i].getLocal_name_ofs_pos());
|
||||
s.writeWChar(type_info_name[i]);
|
||||
}
|
||||
s.pad8bytes();
|
||||
ib.pad8bytes();
|
||||
|
||||
s.setOlderOffsetToThisPos(hdr.getDecl_strings_ofs_pos());
|
||||
//s.seek(hdr.getDeclStringsAddress(), SeekMode.SET);
|
||||
decl_strings.writeToDataStream(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[\r\n");
|
||||
sb.append("name ").append(name).append("\r\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public IggyDeclStrings getDeclStrings() {
|
||||
return decl_strings;
|
||||
}
|
||||
}
|
||||
|
||||
+109
-120
@@ -1,120 +1,109 @@
|
||||
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.Tag;
|
||||
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 {
|
||||
SWF swf = new SWF(is, false, false);
|
||||
SwfToIggyConvertor.updateIggy(iggyFile.getSwf(), swf);
|
||||
iggyFile.saveChanges();
|
||||
return true;
|
||||
} catch (InterruptedException ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
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.streams.SeekableInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
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 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 {
|
||||
SWF swf = new SWF(is, false, false);
|
||||
SwfToIggyConvertor.updateIggy(iggyFile.getSwf(), swf);
|
||||
iggyFile.saveChanges();
|
||||
return true;
|
||||
} catch (InterruptedException ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user