mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-19 14:58:08 +00:00
Merge pull request #44 from jindrapetrik/iggy
Iggy files read support (Fonts only)
This commit is contained in:
4529
CHANGELOG.md
4529
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
2
iggy-extract.bat
Normal file
2
iggy-extract.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
@java -cp lib/ffdec_lib.jar com.jpexs.decompiler.flash.iggy.conversion.IggyToSwfConvertor "%1" "%2"
|
||||
@pause
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,102 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.Path;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWFSourceInfo {
|
||||
|
||||
private final InputStream inputStream;
|
||||
|
||||
private String file;
|
||||
|
||||
private final String fileTitle;
|
||||
|
||||
public SWFSourceInfo(InputStream inputStream, String file, String fileTitle) {
|
||||
this.inputStream = inputStream;
|
||||
this.file = file;
|
||||
this.fileTitle = fileTitle;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public String getFileTitle() {
|
||||
return fileTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title of the file
|
||||
*
|
||||
* @return file title
|
||||
*/
|
||||
public String getFileTitleOrName() {
|
||||
if (fileTitle != null) {
|
||||
return fileTitle;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public boolean isBundle() {
|
||||
if (inputStream == null) {
|
||||
File fileObj = new File(file);
|
||||
String fileName = fileObj.getName();
|
||||
if (fileName.startsWith("asdec_") && fileName.endsWith(".tmp")) {
|
||||
return false;
|
||||
}
|
||||
String extension = Path.getExtension(fileObj);
|
||||
return extension == null || !(extension.equals(".swf") || extension.equals(".gfx"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public SWFBundle getBundle(boolean noCheck, SearchMode searchMode) throws IOException {
|
||||
if (!isBundle()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String extension = Path.getExtension(new File(file));
|
||||
if (extension != null) {
|
||||
switch (extension) {
|
||||
case ".swc":
|
||||
return new SWC(new File(file));
|
||||
case ".zip":
|
||||
return new ZippedSWFBundle(new File(file));
|
||||
}
|
||||
}
|
||||
|
||||
return new BinarySWFBundle(new BufferedInputStream(new FileInputStream(file)), noCheck, searchMode);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.conversion.IggySwfBundle;
|
||||
import com.jpexs.helpers.Path;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWFSourceInfo {
|
||||
|
||||
private final InputStream inputStream;
|
||||
|
||||
private String file;
|
||||
|
||||
private final String fileTitle;
|
||||
|
||||
public SWFSourceInfo(InputStream inputStream, String file, String fileTitle) {
|
||||
this.inputStream = inputStream;
|
||||
this.file = file;
|
||||
this.fileTitle = fileTitle;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public String getFileTitle() {
|
||||
return fileTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title of the file
|
||||
*
|
||||
* @return file title
|
||||
*/
|
||||
public String getFileTitleOrName() {
|
||||
if (fileTitle != null) {
|
||||
return fileTitle;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public boolean isBundle() {
|
||||
if (inputStream == null) {
|
||||
File fileObj = new File(file);
|
||||
String fileName = fileObj.getName();
|
||||
if (fileName.startsWith("asdec_") && fileName.endsWith(".tmp")) {
|
||||
return false;
|
||||
}
|
||||
String extension = Path.getExtension(fileObj);
|
||||
return extension == null || !(extension.equals(".swf") || extension.equals(".gfx"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public SWFBundle getBundle(boolean noCheck, SearchMode searchMode) throws IOException {
|
||||
if (!isBundle()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String extension = Path.getExtension(new File(file));
|
||||
if (extension != null) {
|
||||
switch (extension) {
|
||||
case ".swc":
|
||||
return new SWC(new File(file));
|
||||
case ".zip":
|
||||
return new ZippedSWFBundle(new File(file));
|
||||
case ".iggy":
|
||||
return new IggySwfBundle(new File(file));
|
||||
}
|
||||
}
|
||||
|
||||
return new BinarySWFBundle(new BufferedInputStream(new FileInputStream(file)), noCheck, searchMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class AbstractDataStream {
|
||||
|
||||
/**
|
||||
* Available bytes
|
||||
*
|
||||
* @return null if unknown, long value otherwise
|
||||
*/
|
||||
public abstract Long available();
|
||||
|
||||
public abstract long position();
|
||||
|
||||
public abstract boolean is64();
|
||||
|
||||
protected long readUI64() throws IOException {
|
||||
try {
|
||||
return (readUI32() + (readUI32() << 32)) & 0xffffffffffffffffL;
|
||||
} catch (EOFException ex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean writeUI64(long val) throws IOException {
|
||||
write((int) (val & 0xff));
|
||||
write((int) ((val >> 8) & 0xff));
|
||||
write((int) ((val >> 16) & 0xff));
|
||||
write((int) ((val >> 24) & 0xff));
|
||||
|
||||
write((int) ((val >> 32) & 0xff));
|
||||
write((int) ((val >> 40) & 0xff));
|
||||
write((int) ((val >> 48) & 0xff));
|
||||
write((int) ((val >> 56) & 0xff));
|
||||
return true;
|
||||
}
|
||||
|
||||
protected long readUI32() throws IOException {
|
||||
try {
|
||||
return (readUI8() + (readUI8() << 8) + (readUI8() << 16) + (readUI8() << 24));
|
||||
} catch (EOFException ex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean writeUI32(long val) throws IOException {
|
||||
write((int) (val & 0xff));
|
||||
write((int) ((val >> 8) & 0xff));
|
||||
write((int) ((val >> 16) & 0xff));
|
||||
write((int) ((val >> 24) & 0xff));
|
||||
return true;
|
||||
}
|
||||
|
||||
protected int readUI16() throws IOException {
|
||||
try {
|
||||
return (readUI8() + (readUI8() << 8)) & 0xffff;
|
||||
} catch (EOFException ex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean writeUI16(int val) throws IOException {
|
||||
write(val & 0xff);
|
||||
write((val >> 8) & 0xff);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected int readUI8() throws IOException {
|
||||
try {
|
||||
return read() & 0xff;
|
||||
} catch (EOFException ex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean writeUI8(int val) throws IOException {
|
||||
write(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected float readFloat() throws IOException {
|
||||
return Float.intBitsToFloat((int) readUI32());
|
||||
}
|
||||
|
||||
protected boolean writeFloat(float val) throws IOException {
|
||||
return writeUI32(Float.floatToIntBits(val));
|
||||
}
|
||||
|
||||
protected byte[] readBytes(int numBytes) throws IOException {
|
||||
byte[] ret = new byte[numBytes];
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
ret[i] = (byte) read();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected abstract int read() throws IOException;
|
||||
|
||||
protected abstract void seek(long pos, SeekMode mode) throws IOException;
|
||||
|
||||
protected void write(int val) throws IOException {
|
||||
//nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ByteArrayDataStream extends AbstractDataStream {
|
||||
|
||||
private byte[] data;
|
||||
private long pos;
|
||||
private boolean use64bit;
|
||||
|
||||
public ByteArrayDataStream(int initialSize, boolean use64bit) {
|
||||
this(new byte[initialSize], use64bit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long position() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public ByteArrayDataStream(byte data[], boolean use64bit) {
|
||||
this.data = data;
|
||||
pos = 0;
|
||||
this.use64bit = use64bit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is64() {
|
||||
return use64bit;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int read() throws IOException {
|
||||
if (pos >= data.length) {
|
||||
throw new EOFException("End of stream reached");
|
||||
}
|
||||
int ret = data[(int) pos] & 0xff;
|
||||
pos++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void resize(int newsize) {
|
||||
data = Arrays.copyOf(data, newsize);
|
||||
if (pos > data.length) {
|
||||
pos = data.length;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(int val) throws IOException {
|
||||
if (pos >= data.length) {
|
||||
throw new EOFException("End of stream reached");
|
||||
}
|
||||
data[(int) pos] = (byte) val;
|
||||
pos++;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seek(long pos, SeekMode mode) throws IOException {
|
||||
long newpos = pos;
|
||||
if (mode == SeekMode.CUR) {
|
||||
newpos = this.pos + pos;
|
||||
} else if (mode == SeekMode.END) {
|
||||
newpos = data.length - pos;
|
||||
}
|
||||
if (newpos > data.length) {
|
||||
throw new ArrayIndexOutOfBoundsException("Position outside bounds accessed: " + pos + ". Size: " + data.length);
|
||||
} else if (newpos < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException("Negative position accessed: " + pos);
|
||||
} else {
|
||||
this.pos = (int) newpos;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long available() {
|
||||
return (long) (data.length - pos);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
/**
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum DataType {
|
||||
ubits, uint8_t, uint16_t, uint32_t, uint64_t, float_t, unknown,
|
||||
widechar_t //or maybe just "string"? It has two bytes per character and is null terminated
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyCharAdvances implements StructureInterface {
|
||||
|
||||
List<Float> advances;
|
||||
private long charCount;
|
||||
|
||||
public List<Float> getScales() {
|
||||
return advances;
|
||||
}
|
||||
|
||||
public IggyCharAdvances(AbstractDataStream stream, long charCount) throws IOException {
|
||||
this.charCount = charCount;
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
advances = new ArrayList<>();
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
advances.add(stream.readFloat());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyCharIndices implements StructureInterface {
|
||||
|
||||
@IggyFieldType(value = DataType.widechar_t)
|
||||
List<Character> chars;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long padd;
|
||||
|
||||
public List<Character> getChars() {
|
||||
return chars;
|
||||
}
|
||||
|
||||
private long charCount;
|
||||
|
||||
public IggyCharIndices(AbstractDataStream stream, long charCount) throws IOException {
|
||||
this.charCount = charCount;
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
chars = new ArrayList<>();
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
chars.add((char) stream.readUI16());
|
||||
}
|
||||
padd = stream.readUI32();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyCharKerning implements StructureInterface {
|
||||
|
||||
private long kernCount;
|
||||
List<Character> charsA;
|
||||
List<Character> charsB;
|
||||
List<Short> kerningOffsets;
|
||||
long pad;
|
||||
|
||||
public long getKernCount() {
|
||||
return kernCount;
|
||||
}
|
||||
|
||||
public List<Character> getCharsA() {
|
||||
return charsA;
|
||||
}
|
||||
|
||||
public List<Character> getCharsB() {
|
||||
return charsB;
|
||||
}
|
||||
|
||||
public List<Short> getKerningOffsets() {
|
||||
return kerningOffsets;
|
||||
}
|
||||
|
||||
public IggyCharKerning(AbstractDataStream stream, long kernCount) throws IOException {
|
||||
this.kernCount = kernCount;
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
charsA = new ArrayList<>();
|
||||
charsB = new ArrayList<>();
|
||||
kerningOffsets = new ArrayList<>();
|
||||
for (int i = 0; i < kernCount; i++) {
|
||||
charsA.add((char) stream.readUI16());
|
||||
charsB.add((char) stream.readUI16());
|
||||
kerningOffsets.add((short) stream.readUI16());
|
||||
}
|
||||
pad = stream.readUI32();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyCharOffset implements StructureInterface {
|
||||
|
||||
private static Logger LOGGER = Logger.getLogger(IggyCharOffset.class.getName());
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long zero;
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int ischar1;
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int ischar2;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long zero2;
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int xscale;
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int yscale;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long zero3;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long offset;
|
||||
|
||||
public IggyCharOffset(AbstractDataStream stream) throws IOException {
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
public IggyCharOffset(long zero, int ischar1, int ischar2, long zero2, int xscale, int yscale, long zero3, long offset) {
|
||||
this.zero = zero;
|
||||
this.ischar1 = ischar1;
|
||||
this.ischar2 = ischar2;
|
||||
this.zero2 = zero2;
|
||||
this.xscale = xscale;
|
||||
this.yscale = yscale;
|
||||
this.zero3 = zero3;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
zero = stream.readUI64();
|
||||
ischar1 = stream.readUI16();
|
||||
ischar2 = stream.readUI16();
|
||||
zero2 = stream.readUI32();
|
||||
xscale = stream.readUI16();
|
||||
yscale = stream.readUI16();
|
||||
zero3 = stream.readUI32();
|
||||
long cur_position = stream.position();
|
||||
long relative_offset = stream.readUI64();
|
||||
if (ischar1 > 0) {
|
||||
offset = cur_position + relative_offset;
|
||||
} else {
|
||||
offset = 0;
|
||||
LOGGER.finer(String.format("Empty char"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public long getZero() {
|
||||
return zero;
|
||||
}
|
||||
|
||||
public boolean isChar1() {
|
||||
return ischar1 > 0;
|
||||
}
|
||||
|
||||
public boolean isChar2() {
|
||||
return ischar2 > 0;
|
||||
}
|
||||
|
||||
public long getZero2() {
|
||||
return zero2;
|
||||
}
|
||||
|
||||
public int getXscale() {
|
||||
return xscale;
|
||||
}
|
||||
|
||||
public int getYscale() {
|
||||
return yscale;
|
||||
}
|
||||
|
||||
public long getZero3() {
|
||||
return zero3;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyDataReader implements StructureInterface {
|
||||
|
||||
final static int NO_OFFSET = 1;
|
||||
|
||||
@IggyFieldType(value = DataType.widechar_t, count = 48)
|
||||
String name;
|
||||
|
||||
Map<Integer, IggyFont> fonts;
|
||||
Map<Integer, IggyText> texts;
|
||||
Map<Integer, Integer> text2Font;
|
||||
|
||||
private IggyFlashHeader64 header;
|
||||
private Map<Long, Long> sizesOfOffsets;
|
||||
private List<Long> allOffsets;
|
||||
|
||||
public IggyDataReader(IggyFlashHeader64 header, AbstractDataStream stream, List<Long> offsets) throws IOException {
|
||||
this.header = header;
|
||||
sizesOfOffsets = new HashMap<>();
|
||||
for (int i = 0; i < offsets.size() - 1; i++) {
|
||||
sizesOfOffsets.put(offsets.get(i), offsets.get(i + 1) - offsets.get(i));
|
||||
}
|
||||
sizesOfOffsets.put(offsets.get(offsets.size() - 1), 0L); //Last offset has 0L length?
|
||||
this.allOffsets = offsets;
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
//here is offset[0]
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
do {
|
||||
char c = (char) stream.readUI16();
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
nameBuilder.append(c);
|
||||
} while (true);
|
||||
name = nameBuilder.toString();
|
||||
//here is offset[1]
|
||||
int pad8 = 8 - (int) (stream.position() % 8);
|
||||
stream.seek(pad8, SeekMode.CUR);
|
||||
//here is offset [2]
|
||||
fonts = new HashMap<>();
|
||||
int fontIndex = 0;
|
||||
for (int i = 2; i < allOffsets.size(); i++) {
|
||||
long offset = allOffsets.get(i);
|
||||
stream.seek(offset, SeekMode.SET);
|
||||
int type = stream.readUI16();
|
||||
stream.seek(-2, SeekMode.CUR);
|
||||
if (type == IggyFont.ID) {
|
||||
IggyFont font = new IggyFont(stream);
|
||||
fonts.put(fontIndex++, font);
|
||||
}
|
||||
if (type == IggyText.ID) {
|
||||
//TODO: Texts - incomplete
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,715 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
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.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*
|
||||
* Based of works of somebody called eternity.
|
||||
*
|
||||
*/
|
||||
public class IggyFile extends AbstractDataStream implements AutoCloseable {
|
||||
|
||||
final static Logger LOGGER = Logger.getLogger(IggyFile.class.getName());
|
||||
|
||||
private RandomAccessFile raf;
|
||||
private IggyHeader header;
|
||||
private List<IggySubFileEntry> subFileEntries = new ArrayList<>();
|
||||
|
||||
private List<IggyFlashHeaderInterface> headers = new ArrayList<>();
|
||||
private List<IggyDataReader> flashDataReaders = new ArrayList<>();
|
||||
|
||||
public Set<Integer> getFontIds(int swfIndex) {
|
||||
return flashDataReaders.get(swfIndex).fonts.keySet();
|
||||
}
|
||||
|
||||
public IggyFont getFont(int swfIndex, int fontId) {
|
||||
return flashDataReaders.get(swfIndex).fonts.get(fontId);
|
||||
}
|
||||
|
||||
public IggyText getText(int swfIndex, int textId) {
|
||||
return flashDataReaders.get(swfIndex).texts.get(textId);
|
||||
}
|
||||
|
||||
public Set<Integer> getTextIds(int swfIndex) {
|
||||
return flashDataReaders.get(swfIndex).texts.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long position() {
|
||||
try {
|
||||
return raf.getFilePointer();
|
||||
} catch (IOException ex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public IggyFile(File file) throws IOException {
|
||||
raf = new RandomAccessFile(file, "r");
|
||||
header = new IggyHeader(this);
|
||||
for (int i = 0; i < header.getNumSubfiles(); i++) {
|
||||
subFileEntries.add(new IggySubFileEntry(this));
|
||||
}
|
||||
|
||||
List<List<Integer>> indexTables = new ArrayList<>(); //TODO: use this two for something ??
|
||||
List<List<Long>> offsetTables = new ArrayList<>();
|
||||
List<AbstractDataStream> flashDataStreams = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < subFileEntries.size(); i++) {
|
||||
IggySubFileEntry entry = subFileEntries.get(i);
|
||||
ByteArrayDataStream dataStream = getEntryDataStream(i);
|
||||
if (entry.type == IggySubFileEntry.TYPE_INDEX) {
|
||||
List<Integer> indexTable = new ArrayList<>();
|
||||
List<Long> offsets = new ArrayList<>();
|
||||
IggyIndexParser.parseIndex(dataStream, indexTable, offsets);
|
||||
indexTables.add(indexTable);
|
||||
offsetTables.add(offsets);
|
||||
} else if (entry.type == IggySubFileEntry.TYPE_FLASH) {
|
||||
IggyFlashHeaderInterface hdr;
|
||||
if (is64()) {
|
||||
hdr = new IggyFlashHeader64(dataStream);
|
||||
} else {
|
||||
hdr = new IggyFlashHeader32(dataStream);
|
||||
}
|
||||
headers.add(hdr);
|
||||
flashDataStreams.add(dataStream);
|
||||
}
|
||||
}
|
||||
|
||||
for (int swfIndex = 0; swfIndex < headers.size(); swfIndex++) {
|
||||
IggyFlashHeaderInterface hdr = headers.get(swfIndex);
|
||||
IggyDataReader dataReader = new IggyDataReader((IggyFlashHeader64) hdr /*FIXME for 32*/, flashDataStreams.get(swfIndex), offsetTables.get(swfIndex));
|
||||
flashDataReaders.add(dataReader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is64() {
|
||||
return header.is64();
|
||||
}
|
||||
|
||||
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) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = getEntryInputStream(entryIndex);
|
||||
byte buf[] = new byte[1024];
|
||||
int cnt;
|
||||
while ((cnt = is.read(buf)) > 0) {
|
||||
baos.write(buf, 0, cnt);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public ByteArrayDataStream getEntryDataStream(int entryIndex) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = getEntryInputStream(entryIndex);
|
||||
byte buf[] = new byte[1024];
|
||||
int cnt;
|
||||
while ((cnt = is.read(buf)) > 0) {
|
||||
baos.write(buf, 0, cnt);
|
||||
}
|
||||
byte data[] = baos.toByteArray();
|
||||
return new ByteArrayDataStream(data, is64());
|
||||
}
|
||||
|
||||
public InputStream getEntryInputStream(int entryIndex) {
|
||||
IggySubFileEntry entry = getSubFileEntry(entryIndex);
|
||||
|
||||
return new InputStream() {
|
||||
long offset = entry.offset;
|
||||
long maxOffset = entry.offset + entry.size;
|
||||
|
||||
@Override
|
||||
public synchronized int read() throws IOException {
|
||||
if (offset < maxOffset) {
|
||||
raf.seek(offset);
|
||||
offset++;
|
||||
return raf.read();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int read() throws IOException {
|
||||
int val = raf.read();
|
||||
if (val == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@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";
|
||||
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)))) {
|
||||
fos.write(ir.getEntryData(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processFile(File f) {
|
||||
if (f.isDirectory()) {
|
||||
System.out.println("Processing directory " + f + ":");
|
||||
File iggyFiles[] = f.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".iggy");
|
||||
}
|
||||
});
|
||||
for (File sf : iggyFiles) {
|
||||
processFile(sf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
System.out.print("Processing file " + f + "...");
|
||||
try {
|
||||
File dir = f.getParentFile();
|
||||
File extractDir = new File(dir, "extracted_" + (f.getName()).replace(".iggy", ""));
|
||||
extractDir.mkdir();
|
||||
extractIggyFile(f, extractDir);
|
||||
System.out.println("OK");
|
||||
} catch (Exception ex) {
|
||||
System.err.println("FAIL");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.out.println("Iggy file splitter");
|
||||
if (args.length == 0) {
|
||||
System.err.println("No file specified");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
for (String s : args) {
|
||||
File f = new File(s);
|
||||
if (!f.exists()) {
|
||||
System.err.println("File " + f + " does not exists");
|
||||
System.exit(1);
|
||||
}
|
||||
processFile(f);
|
||||
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private static void copyStream(InputStream is, OutputStream os) {
|
||||
try {
|
||||
final int bufSize = 4096;
|
||||
byte[] buf = new byte[bufSize];
|
||||
int cnt;
|
||||
while ((cnt = is.read(buf)) > 0) {
|
||||
os.write(buf, 0, cnt);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seek(long pos, SeekMode mode) throws IOException {
|
||||
long newpos = pos;
|
||||
if (mode == SeekMode.CUR) {
|
||||
newpos = raf.getFilePointer() + pos;
|
||||
} else if (mode == SeekMode.END) {
|
||||
newpos = raf.length() - pos;
|
||||
}
|
||||
if (newpos > raf.length()) {
|
||||
throw new ArrayIndexOutOfBoundsException("Position outside bounds accessed: " + pos + ". Size: " + raf.length());
|
||||
} else if (newpos < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException("Negative position accessed: " + pos);
|
||||
} else {
|
||||
raf.seek(newpos);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean updateIndex(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], long item_size_change /*int32_t*/) throws IOException {
|
||||
ByteArrayDataStream stream = new ByteArrayDataStream(index_bytes, is_64);
|
||||
|
||||
/*
|
||||
index_table:
|
||||
n = UI8
|
||||
for i=0..n-1
|
||||
table[i] = UI8
|
||||
cnt = UI8
|
||||
cnt * UI16
|
||||
|
||||
*/
|
||||
int index_table_size = stream.readUI8();
|
||||
int index_table[] = new int[index_table_size];
|
||||
|
||||
for (int i = 0; i < index_table_size; i++) {
|
||||
index_table[i] = stream.readUI8();
|
||||
int num = stream.readUI8();
|
||||
stream.seek(num * 2, SeekMode.CUR);
|
||||
//num * UI16
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
long offset = 0;//uint32_t
|
||||
int code; //uint8_t
|
||||
|
||||
while ((code = stream.readUI8()) >= 0) {
|
||||
if (state == 1) {
|
||||
if (code != 0xFD) {
|
||||
LOGGER.log(Level.WARNING, "We were expecting code 0xFD in state 1.");
|
||||
return false;
|
||||
}
|
||||
} else if (state == 2) {
|
||||
if (code != 0xFF) {
|
||||
LOGGER.log(Level.WARNING, "We were expecting code 0xFF in state 2.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (code < 0x80) // 0-0x7F
|
||||
{
|
||||
// code is directly an index to the index_table
|
||||
if (code >= index_table_size) {
|
||||
LOGGER.log(Level.WARNING, String.format("< 0x80: index is greater than index_table_size. %x > %x", code, index_table_size));
|
||||
return false;
|
||||
}
|
||||
|
||||
offset += index_table[code];
|
||||
} else if (code < 0xC0) // 0x80-BF
|
||||
{
|
||||
int index; //uint8_t
|
||||
|
||||
if ((index = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "< 0xC0: Cannot read index.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= index_table_size) {
|
||||
LOGGER.log(Level.WARNING, String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, index_table_size));
|
||||
return false;
|
||||
}
|
||||
|
||||
int n = code - 0x7F;
|
||||
offset += index_table[index] * n;
|
||||
} else if (code < 0xD0) // 0xC0-0xCF
|
||||
{
|
||||
offset += ((code * 2) - 0x17E);
|
||||
} else if (code < 0xE0) // 0xD0-0xDF
|
||||
{
|
||||
// Code here depends on plattform[0], we are assuming it is 1, as we checked in load function
|
||||
int i = code & 0xF; //uint8_t
|
||||
int n8; //uint8_t
|
||||
int n;
|
||||
|
||||
if ((n8 = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "< 0xE0: Cannot read n.");
|
||||
return false;
|
||||
}
|
||||
|
||||
n = n8 + 1;
|
||||
|
||||
if (is_64) {
|
||||
if (i <= 2) {
|
||||
offset += 8 * n; // Ptr type
|
||||
} else if (i <= 4) {
|
||||
offset += 2 * n;
|
||||
} else if (i == 5) {
|
||||
offset += 4 * n;
|
||||
} else if (i == 6) {
|
||||
offset += 8 * n; // 64 bits type
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, String.format("< 0xE0: Invalid value for i (%x %x)", i, code));
|
||||
}
|
||||
} else {
|
||||
switch (i) {
|
||||
case 2:
|
||||
offset += 4 * n; // Ptr type
|
||||
break;
|
||||
case 4:
|
||||
offset += 2 * n;
|
||||
break;
|
||||
case 5:
|
||||
offset += 4 * n; // 32 bits type
|
||||
break;
|
||||
case 6:
|
||||
offset += 8 * n;
|
||||
break;
|
||||
default:
|
||||
LOGGER.log(Level.WARNING, String.format("< 0xE0: invalid value for i (%x %x)", i, code));
|
||||
}
|
||||
}
|
||||
} else if (code == 0xFC) {
|
||||
stream.seek(1, SeekMode.CUR);
|
||||
} else if (code == 0xFD) {
|
||||
int n, m; //uint8_t
|
||||
|
||||
if ((n = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "0xFD: Cannot read n.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state == 1) {
|
||||
if (is_64) {
|
||||
if (n != 0xF) {
|
||||
LOGGER.log(Level.WARNING, String.format("We were expecting an offset of 0xF in state 1."));
|
||||
return false;
|
||||
}
|
||||
} else if (n != 0xB) {
|
||||
LOGGER.log(Level.WARNING, "We were expecting an offset of 0xB in state 1.");
|
||||
return false;
|
||||
}
|
||||
|
||||
state = 2;
|
||||
}
|
||||
|
||||
if ((m = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "0xFD: Cannot read m.");
|
||||
return false;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
stream.seek(m * 2, SeekMode.CUR);
|
||||
} else if (code == 0xFE) {
|
||||
int n8; //uint8_t
|
||||
int n;
|
||||
|
||||
if ((n8 = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "0xFE: Cannot read n.");
|
||||
return false;
|
||||
}
|
||||
|
||||
n = n8 + 1;
|
||||
offset += n;
|
||||
} else if (code == 0xFF) {
|
||||
long n; //uint32_t
|
||||
|
||||
if ((n = stream.readUI32()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "0xFF: Cannot read n.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state == 2) {
|
||||
n += item_size_change;
|
||||
stream.seek(-4, SeekMode.CUR);
|
||||
return stream.writeUI32(n);
|
||||
}
|
||||
|
||||
offset += n;
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, String.format("Unrecognized code: %x", code));
|
||||
}
|
||||
|
||||
if (state == 0 && offset == item_offset) {
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets length of an item.
|
||||
*
|
||||
* @param item_offset
|
||||
* @param is_64
|
||||
* @param index_bytes
|
||||
* @return null when item not exists, item length otherwise
|
||||
* @throws IOException
|
||||
*/
|
||||
private static Long getItemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[]) throws IOException {
|
||||
return itemLength(item_offset, is_64, index_bytes, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets new length of an item.
|
||||
*
|
||||
* @param item_offset
|
||||
* @param is_64
|
||||
* @param index_bytes
|
||||
* @param newLength
|
||||
* @return null when item not exists, old item length otherwise
|
||||
* @throws IOException
|
||||
*/
|
||||
private static Long setItemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], long newLength) throws IOException {
|
||||
return itemLength(item_offset, is_64, index_bytes, newLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets/Gets length of an item
|
||||
*
|
||||
* @param item_offset
|
||||
* @param is_64
|
||||
* @param index_bytes
|
||||
* @param newValue New value to set. If null then no change.
|
||||
* @return null when item does not exists, old item length otherwise
|
||||
* @throws IOException
|
||||
*/
|
||||
private static Long itemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], Long newValue) throws IOException {
|
||||
ByteArrayDataStream stream = new ByteArrayDataStream(index_bytes, is_64);
|
||||
|
||||
/*
|
||||
index_table:
|
||||
n = UI8
|
||||
for i=0..n-1
|
||||
table[i] = UI8
|
||||
cnt = UI8
|
||||
cnt * UI16
|
||||
|
||||
*/
|
||||
int index_table_size = stream.readUI8();
|
||||
int index_table[] = new int[index_table_size];
|
||||
|
||||
for (int i = 0; i < index_table_size; i++) {
|
||||
index_table[i] = stream.readUI8();
|
||||
int num = stream.readUI8();
|
||||
stream.seek(num * 2, SeekMode.CUR);
|
||||
//num * UI16
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
long offset = 0;//uint32_t
|
||||
int code; //uint8_t
|
||||
|
||||
while ((code = stream.readUI8()) >= 0) {
|
||||
if (state == 1) {
|
||||
if (code != 0xFD) {
|
||||
LOGGER.log(Level.WARNING, "We were expecting code 0xFD in state 1.");
|
||||
return null;
|
||||
}
|
||||
} else if (state == 2) {
|
||||
if (code != 0xFF) {
|
||||
LOGGER.log(Level.WARNING, "We were expecting code 0xFF in state 2.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (code < 0x80) // 0-0x7F
|
||||
{
|
||||
// code is directly an index to the index_table
|
||||
if (code >= index_table_size) {
|
||||
LOGGER.log(Level.WARNING, String.format("< 0x80: index is greater than index_table_size. %x > %x", code, index_table_size));
|
||||
return null;
|
||||
}
|
||||
|
||||
offset += index_table[code];
|
||||
} else if (code < 0xC0) // 0x80-BF
|
||||
{
|
||||
int index; //uint8_t
|
||||
|
||||
if ((index = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "< 0xC0: Cannot read index.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (index >= index_table_size) {
|
||||
LOGGER.log(Level.WARNING, String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, index_table_size));
|
||||
return null;
|
||||
}
|
||||
|
||||
int n = code - 0x7F;
|
||||
offset += index_table[index] * n;
|
||||
} else if (code < 0xD0) // 0xC0-0xCF
|
||||
{
|
||||
offset += ((code * 2) - 0x17E);
|
||||
} else if (code < 0xE0) // 0xD0-0xDF
|
||||
{
|
||||
// Code here depends on plattform[0], we are assuming it is 1, as we checked in load function
|
||||
int i = code & 0xF; //uint8_t
|
||||
int n8; //uint8_t
|
||||
int n;
|
||||
|
||||
if ((n8 = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "< 0xE0: Cannot read n.");
|
||||
return null;
|
||||
}
|
||||
|
||||
n = n8 + 1;
|
||||
|
||||
if (is_64) {
|
||||
if (i <= 2) {
|
||||
offset += 8 * n; // Ptr type
|
||||
} else if (i <= 4) {
|
||||
offset += 2 * n;
|
||||
} else if (i == 5) {
|
||||
offset += 4 * n;
|
||||
} else if (i == 6) {
|
||||
offset += 8 * n; // 64 bits type
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, String.format("< 0xE0: Invalid value for i (%x %x)", i, code));
|
||||
}
|
||||
} else {
|
||||
switch (i) {
|
||||
case 2:
|
||||
offset += 4 * n; // Ptr type
|
||||
break;
|
||||
case 4:
|
||||
offset += 2 * n;
|
||||
break;
|
||||
case 5:
|
||||
offset += 4 * n; // 32 bits type
|
||||
break;
|
||||
case 6:
|
||||
offset += 8 * n;
|
||||
break;
|
||||
default:
|
||||
LOGGER.log(Level.WARNING, String.format("< 0xE0: invalid value for i (%x %x)", i, code));
|
||||
}
|
||||
}
|
||||
} else if (code == 0xFC) {
|
||||
stream.seek(1, SeekMode.CUR);
|
||||
} else if (code == 0xFD) {
|
||||
int n, m; //uint8_t
|
||||
|
||||
if ((n = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "0xFD: Cannot read n.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (state == 1) {
|
||||
if (is_64) {
|
||||
if (n != 0xF) {
|
||||
LOGGER.log(Level.WARNING, String.format("We were expecting an offset of 0xF in state 1."));
|
||||
return null;
|
||||
}
|
||||
} else if (n != 0xB) {
|
||||
LOGGER.log(Level.WARNING, "We were expecting an offset of 0xB in state 1.");
|
||||
return null;
|
||||
}
|
||||
|
||||
state = 2;
|
||||
}
|
||||
|
||||
if ((m = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "0xFD: Cannot read m.");
|
||||
return null;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
stream.seek(m * 2, SeekMode.CUR);
|
||||
} else if (code == 0xFE) {
|
||||
int n8; //uint8_t
|
||||
int n;
|
||||
|
||||
if ((n8 = stream.readUI8()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "0xFE: Cannot read n.");
|
||||
return null;
|
||||
}
|
||||
|
||||
n = n8 + 1;
|
||||
offset += n;
|
||||
} else if (code == 0xFF) {
|
||||
long n; //uint32_t
|
||||
|
||||
if ((n = stream.readUI32()) < 0) {
|
||||
LOGGER.log(Level.WARNING, "0xFF: Cannot read n.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (state == 2) {
|
||||
if (newValue != null) {
|
||||
stream.seek(-4, SeekMode.CUR);
|
||||
stream.writeUI32(newValue);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, String.format("Unrecognized code: %x", code));
|
||||
}
|
||||
|
||||
if (state == 0 && offset == item_offset) {
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long available() {
|
||||
try {
|
||||
return raf.length() - raf.getFilePointer();
|
||||
} catch (IOException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSwfCount() {
|
||||
return flashDataReaders.size();
|
||||
}
|
||||
|
||||
public String getSwfName(int swfIndex) {
|
||||
return flashDataReaders.get(swfIndex).getName();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*
|
||||
* Based of works of somebody called eternity.
|
||||
*
|
||||
* All relative offsets are relative from that specific field position All
|
||||
* relative offsets can get value "1" to indicate "nothing"
|
||||
*/
|
||||
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;
|
||||
|
||||
// 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.
|
||||
// After the offsets, the bodies of objects pointed above, which apparently have a code like 0xFFXX to identify the type of object, followed by a (unique?) identifier
|
||||
// for the object.
|
||||
// A DefineEditText-like object can be easily spotted and apparently uses type code 0x06 (or 0xFF06) but as stated above,
|
||||
// it is written in a different way.
|
||||
public IggyFlashHeader32(AbstractDataStream stream) throws IOException {
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
main_offset = stream.readUI32();
|
||||
as3_section_offset = stream.readUI32();
|
||||
unk_offset = stream.readUI32();
|
||||
unk_offset2 = stream.readUI32();
|
||||
unk_offset3 = stream.readUI32();
|
||||
unk_offset4 = stream.readUI32();
|
||||
xmin = stream.readUI32();
|
||||
ymin = stream.readUI32();
|
||||
xmax = stream.readUI32();
|
||||
ymax = stream.readUI32();
|
||||
unk_28 = stream.readUI32();
|
||||
unk_2C = stream.readUI32();
|
||||
unk_30 = stream.readUI32();
|
||||
unk_34 = stream.readUI32();
|
||||
unk_38 = stream.readUI32();
|
||||
unk_3C = stream.readUI32();
|
||||
frameRate = stream.readFloat();
|
||||
unk_44 = stream.readUI32();
|
||||
unk_48 = stream.readUI32();
|
||||
unk_4C = stream.readUI32();
|
||||
unk_3C = stream.readUI32();
|
||||
names_offset = stream.readUI32();
|
||||
unk_offset5 = stream.readUI32();
|
||||
unk_58 = stream.readUI64();
|
||||
last_section_offset = stream.readUI32();
|
||||
unk_offset6 = stream.readUI32();
|
||||
as3_code_offset = stream.readUI32();
|
||||
as3_names_offset = stream.readUI32();
|
||||
unk_70 = stream.readUI32();
|
||||
unk_74 = stream.readUI32();
|
||||
unk_78 = stream.readUI32();
|
||||
unk_7C = stream.readUI32();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("[\r\n");
|
||||
sb.append("main_offset ").append(main_offset).append("\r\n");
|
||||
sb.append("as3_section_offset ").append(as3_section_offset).append("\r\n");
|
||||
sb.append("unk_offset ").append(unk_offset).append("\r\n");
|
||||
sb.append("unk_offset2 ").append(unk_offset2).append("\r\n");
|
||||
sb.append("unk_offset3 ").append(unk_offset3).append("\r\n");
|
||||
sb.append("unk_offset4 ").append(unk_offset4).append("\r\n");
|
||||
sb.append("xmin ").append(xmin).append("\r\n");
|
||||
sb.append("ymin ").append(ymin).append("\r\n");
|
||||
sb.append("xmax ").append(xmax).append("\r\n");
|
||||
sb.append("ymax ").append(ymax).append("\r\n");
|
||||
sb.append("unk_28 ").append(unk_28).append("\r\n");
|
||||
sb.append("unk_2C ").append(unk_2C).append("\r\n");
|
||||
sb.append("unk_30 ").append(unk_30).append("\r\n");
|
||||
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("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");
|
||||
sb.append("names_offset ").append(names_offset).append("\r\n");
|
||||
sb.append("unk_offset5 ").append(unk_offset5).append("\r\n");
|
||||
sb.append("unk_58 ").append(unk_58).append("\r\n");
|
||||
sb.append("last_section_offset ").append(last_section_offset).append("\r\n");
|
||||
sb.append("unk_offset6 ").append(unk_offset6).append("\r\n");
|
||||
sb.append("as3_code_offset ").append(as3_code_offset).append("\r\n");
|
||||
sb.append("as3_names_offset ").append(as3_names_offset).append("\r\n");
|
||||
sb.append("unk_70 ").append(unk_70).append("\r\n");
|
||||
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("]");
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jindra
|
||||
*
|
||||
* Based of works of somebody called eternity.
|
||||
*/
|
||||
public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
|
||||
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long main_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)
|
||||
long unk_offset; // 0x10 relative offset to something
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long unk_offset2; // 0x18 relative offset to something
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long unk_offset3; // 0x20 relative offset to something
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long unk_offset4; // 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
|
||||
@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 fonts_offset;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long unk_68;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
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)
|
||||
long unk_80; // Maybe number of imports/names pointed by names_offset
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long last_section_offset; // 0x88 relative offset, points to the small last section of the file
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long unk_offset6; // 0x90 relative offset to something
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long as3_code_offset; // 0x98 relative offset to as3 code (16 bytes header + abc blob)
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
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_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.
|
||||
// After the offsets, the bodies of objects pointed above, which apparently have a code like 0xFFXX to identify the type of object, followed by a (unique?) identifier
|
||||
// for the object.
|
||||
// A DefineEditText-like object can be easily spotted and apparently uses type code 0x06 (or 0xFF06) but as stated above,
|
||||
// it is written in a different way.
|
||||
public IggyFlashHeader64(AbstractDataStream stream) throws IOException {
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
main_offset = stream.readUI64();
|
||||
as3_section_offset = stream.readUI64();
|
||||
unk_offset = stream.readUI64();
|
||||
unk_offset2 = stream.readUI64();
|
||||
unk_offset3 = stream.readUI64();
|
||||
unk_offset4 = stream.readUI64();
|
||||
xmin = stream.readUI32();
|
||||
ymin = stream.readUI32();
|
||||
xmax = stream.readUI32();
|
||||
ymax = stream.readUI32();
|
||||
unk_40 = stream.readUI32();
|
||||
unk_44 = stream.readUI32();
|
||||
unk_48 = stream.readUI32();
|
||||
unk_4C = stream.readUI32();
|
||||
unk_50 = stream.readUI32();
|
||||
unk_54 = stream.readUI32();
|
||||
frame_rate = stream.readFloat();
|
||||
unk_5C = stream.readUI32();
|
||||
fonts_offset = stream.readUI64();
|
||||
unk_68 = stream.readUI64();
|
||||
names_offset = stream.readUI64();
|
||||
unk_offset5 = stream.readUI64();
|
||||
unk_80 = stream.readUI64();
|
||||
last_section_offset = stream.readUI64();
|
||||
unk_offset6 = stream.readUI64();
|
||||
as3_code_offset = stream.readUI64();
|
||||
as3_names_offset = stream.readUI64();
|
||||
unk_A8 = stream.readUI32();
|
||||
unk_AC = stream.readUI32();
|
||||
font_count = stream.readUI32();
|
||||
unk_B4 = stream.readUI32();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[\r\n");
|
||||
sb.append("main_offset ").append(main_offset).append("\r\n");
|
||||
sb.append("as3_section_offset ").append(as3_section_offset);
|
||||
sb.append(" global: ").append(main_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("\r\n");
|
||||
sb.append("unk_offset2 ").append(unk_offset2);
|
||||
if (unk_offset2 != 1) {
|
||||
sb.append(" global: ").append(main_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("\r\n");
|
||||
sb.append("unk_offset4 ").append(unk_offset4);
|
||||
if (unk_offset4 != 1) {
|
||||
sb.append(" global: ").append(main_offset + unk_offset4);
|
||||
}
|
||||
sb.append("\r\n");
|
||||
sb.append("xmin ").append(xmin).append("\r\n");
|
||||
sb.append("ymin ").append(ymin).append("\r\n");
|
||||
sb.append("xmax ").append(ymax).append("\r\n");
|
||||
sb.append("ymax ").append(ymax).append("\r\n");
|
||||
sb.append("unk_40 ").append(unk_40).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");
|
||||
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("unk_5C ").append(unk_5C).append("\r\n");
|
||||
sb.append("fonts_offset ").append(fonts_offset).append("\r\n");
|
||||
sb.append("unk_68 ").append(unk_68).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");
|
||||
sb.append("last_section_offset ").append(last_section_offset).append("\r\n");
|
||||
sb.append("unk_offset6 ").append(unk_offset6).append("\r\n");
|
||||
sb.append("as3_code_offset ").append(as3_code_offset).append("\r\n");
|
||||
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("font_count ").append(font_count).append("\r\n");
|
||||
sb.append("unk_B4 ").append(unk_B4).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 frame_rate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface IggyFlashHeaderInterface extends StructureInterface {
|
||||
|
||||
public long getXMin();
|
||||
|
||||
public long getYMin();
|
||||
|
||||
public long getXMax();
|
||||
|
||||
public long getYMax();
|
||||
|
||||
public float getFrameRate();
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
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 IggyFont implements StructureInterface {
|
||||
|
||||
public static final int ID = 0xFF16;
|
||||
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int type; //stejny pro rozdilne fonty
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int fontId;
|
||||
@IggyArrayFieldType(value = DataType.uint8_t, count = 28)
|
||||
byte[] zeroone; // stejny pro rozdilne fonty
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int char_count2;
|
||||
@IggyFieldType(value = DataType.uint16_t)
|
||||
int ascent;
|
||||
@IggyFieldType(value = DataType.uint16_t)
|
||||
int descent;
|
||||
@IggyFieldType(value = DataType.uint16_t)
|
||||
int leading;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long flags;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long start_of_char_struct;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long start_of_char_index;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long start_of_scale;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long kern_count;
|
||||
@IggyArrayFieldType(value = DataType.float_t, count = 5)
|
||||
float[] unk_float;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long start_of_kern;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long zero_padd;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long what_2;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long zero_padd_2;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long start_of_name;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long one_padd;
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int xscale;
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int yscale;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long zero_padd_3;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float ssr1;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float ssr2;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long char_count;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long zero_padd_4;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long what_3;
|
||||
@IggyFieldType(value = DataType.uint8_t, count = 272)
|
||||
byte[] zeroes;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float sss1;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long one_padd2;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float sss2;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long one_padd3;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float sss3;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long one_padd4;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float sss4;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long one_padd5;
|
||||
|
||||
@IggyFieldType(value = DataType.widechar_t, count = 16)
|
||||
String name;
|
||||
|
||||
List<IggyCharOffset> charOffsets;
|
||||
List<IggyShape> glyphs;
|
||||
IggyCharIndices codePoints;
|
||||
IggyCharAdvances charScales;
|
||||
IggyCharKerning charKernings;
|
||||
|
||||
byte[] padTo4byteBoundary;
|
||||
|
||||
public IggyFont(int type, int order_in_iggy_file, byte[] zeroone, int char_count2, int ascent, int descent, int leading, long flags, long start_of_char_struct, long start_of_char_index, long start_of_scale, long kern_count, float[] unk_float, long start_of_kern, long zero_padd, long what_2, long zero_padd_2, long start_of_name, long one_padd, int xscale, int yscale, long zero_padd_3, float ssr1, float ssr2, long char_count, long zero_padd_4, long what_3, byte[] zeroes, float sss1, long one_padd2, float sss2, long one_padd3, float sss3, long one_padd4, float sss4, long one_padd5, String name, List<IggyCharOffset> charOffsets, List<IggyShape> chars, IggyCharIndices charIndices, IggyCharAdvances charScales, IggyCharKerning charKernings, byte[] padTo4byteBoundary) {
|
||||
this.type = type;
|
||||
this.fontId = order_in_iggy_file;
|
||||
this.zeroone = zeroone;
|
||||
this.char_count2 = char_count2;
|
||||
this.ascent = ascent;
|
||||
this.descent = descent;
|
||||
this.leading = leading;
|
||||
this.flags = flags;
|
||||
this.start_of_char_struct = start_of_char_struct;
|
||||
this.start_of_char_index = start_of_char_index;
|
||||
this.start_of_scale = start_of_scale;
|
||||
this.kern_count = kern_count;
|
||||
this.unk_float = unk_float;
|
||||
this.start_of_kern = start_of_kern;
|
||||
this.zero_padd = zero_padd;
|
||||
this.what_2 = what_2;
|
||||
this.zero_padd_2 = zero_padd_2;
|
||||
this.start_of_name = start_of_name;
|
||||
this.one_padd = one_padd;
|
||||
this.xscale = xscale;
|
||||
this.yscale = yscale;
|
||||
this.zero_padd_3 = zero_padd_3;
|
||||
this.ssr1 = ssr1;
|
||||
this.ssr2 = ssr2;
|
||||
this.char_count = char_count;
|
||||
this.zero_padd_4 = zero_padd_4;
|
||||
this.what_3 = what_3;
|
||||
this.zeroes = zeroes;
|
||||
this.sss1 = sss1;
|
||||
this.one_padd2 = one_padd2;
|
||||
this.sss2 = sss2;
|
||||
this.one_padd3 = one_padd3;
|
||||
this.sss3 = sss3;
|
||||
this.one_padd4 = one_padd4;
|
||||
this.sss4 = sss4;
|
||||
this.one_padd5 = one_padd5;
|
||||
this.name = name;
|
||||
this.charOffsets = charOffsets;
|
||||
this.glyphs = chars;
|
||||
this.codePoints = charIndices;
|
||||
this.charScales = charScales;
|
||||
this.charKernings = charKernings;
|
||||
this.padTo4byteBoundary = padTo4byteBoundary;
|
||||
}
|
||||
|
||||
public IggyFont(AbstractDataStream stream) throws IOException {
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
private long readAbsoluteOffset(AbstractDataStream stream) throws IOException {
|
||||
long offset = stream.readUI64();
|
||||
if (offset == 1) {
|
||||
return 0;
|
||||
}
|
||||
return stream.position() - 8 + offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
ByteArrayDataStream s = new ByteArrayDataStream(stream.readBytes((int) (long) stream.available()), stream.is64());
|
||||
type = s.readUI16();
|
||||
fontId = s.readUI16();
|
||||
zeroone = s.readBytes(28);
|
||||
char_count2 = s.readUI16();
|
||||
ascent = s.readUI16();
|
||||
descent = s.readUI16();
|
||||
leading = s.readUI16();
|
||||
flags = s.readUI64();
|
||||
start_of_char_struct = readAbsoluteOffset(s);
|
||||
start_of_char_index = readAbsoluteOffset(s);
|
||||
start_of_scale = readAbsoluteOffset(s);
|
||||
kern_count = s.readUI32();
|
||||
unk_float = new float[5];
|
||||
for (int i = 0; i < unk_float.length; i++) {
|
||||
unk_float[i] = s.readFloat();
|
||||
}
|
||||
start_of_kern = readAbsoluteOffset(s);
|
||||
zero_padd = s.readUI64();
|
||||
what_2 = s.readUI64();
|
||||
zero_padd_2 = s.readUI64();
|
||||
start_of_name = readAbsoluteOffset(s);
|
||||
one_padd = s.readUI64();
|
||||
xscale = s.readUI16();
|
||||
yscale = s.readUI16();
|
||||
zero_padd_3 = s.readUI64();
|
||||
ssr1 = s.readFloat();
|
||||
ssr2 = s.readFloat();
|
||||
char_count = s.readUI32();
|
||||
zero_padd_4 = s.readUI64();
|
||||
what_3 = s.readUI64();
|
||||
s.seek(272, SeekMode.CUR);
|
||||
sss1 = s.readFloat();
|
||||
one_padd2 = s.readUI32();
|
||||
sss2 = s.readFloat();
|
||||
one_padd3 = s.readUI32();
|
||||
sss3 = s.readFloat();
|
||||
one_padd4 = s.readUI32();
|
||||
sss4 = s.readFloat();
|
||||
one_padd5 = s.readUI32();
|
||||
if (start_of_name != 0) {
|
||||
s.seek(start_of_name, SeekMode.SET);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
int nameCharCnt = 0;
|
||||
do {
|
||||
char c = (char) s.readUI16();
|
||||
nameCharCnt++;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
nameBuilder.append(c);
|
||||
} while (true);
|
||||
s.seek(32 - nameCharCnt * 2, SeekMode.CUR);
|
||||
name = nameBuilder.toString();
|
||||
}
|
||||
s.readUI64(); //pad zero
|
||||
if (start_of_char_struct != 0) {
|
||||
s.seek(start_of_char_struct, SeekMode.SET);
|
||||
charOffsets = new ArrayList<>();
|
||||
for (int i = 0; i < char_count; i++) {
|
||||
charOffsets.add(new IggyCharOffset(s));
|
||||
}
|
||||
glyphs = new ArrayList<>();
|
||||
for (int i = 0; i < char_count; i++) {
|
||||
long offset = charOffsets.get(i).offset;
|
||||
glyphs.add(new IggyShape(s, offset));
|
||||
}
|
||||
}
|
||||
if (start_of_char_index != 0) {
|
||||
s.seek(start_of_char_index, SeekMode.SET);
|
||||
codePoints = new IggyCharIndices(s, char_count);
|
||||
}
|
||||
if (start_of_scale != 0) {
|
||||
s.seek(start_of_scale, SeekMode.SET);
|
||||
charScales = new IggyCharAdvances(s, char_count);
|
||||
}
|
||||
if (start_of_kern != 0) {
|
||||
s.seek(start_of_kern, SeekMode.SET);
|
||||
charKernings = new IggyCharKerning(s, kern_count);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public long getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public int getXscale() {
|
||||
return xscale;
|
||||
}
|
||||
|
||||
public int getYscale() {
|
||||
return yscale;
|
||||
}
|
||||
|
||||
public long getCharacterCount() {
|
||||
return char_count;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<IggyShape> getChars() {
|
||||
return glyphs;
|
||||
}
|
||||
|
||||
public IggyCharIndices getCharIndices() {
|
||||
return codePoints;
|
||||
}
|
||||
|
||||
public IggyCharAdvances getCharAdvances() {
|
||||
return charScales;
|
||||
}
|
||||
|
||||
public IggyCharKerning getCharKernings() {
|
||||
return charKernings;
|
||||
}
|
||||
|
||||
public float[] getUnk_float() {
|
||||
return unk_float;
|
||||
}
|
||||
|
||||
public int getAscent() {
|
||||
return ascent;
|
||||
}
|
||||
|
||||
public int getDescent() {
|
||||
return descent;
|
||||
}
|
||||
|
||||
public int getLeading() {
|
||||
return leading;
|
||||
}
|
||||
|
||||
public long getWhat_2() {
|
||||
return what_2;
|
||||
}
|
||||
|
||||
public long getWhat_3() {
|
||||
return what_3;
|
||||
}
|
||||
|
||||
public List<IggyCharOffset> getCharOffsets() {
|
||||
return charOffsets;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*
|
||||
* little endian all
|
||||
*
|
||||
* Based of works of somebody called eternity.
|
||||
*/
|
||||
public class IggyHeader implements StructureInterface {
|
||||
|
||||
public static long MAGIC = 0xED0A6749;
|
||||
|
||||
//Must be 0xED0A6749
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
private long magic = MAGIC;
|
||||
|
||||
//Assume 0x900
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
private long version;
|
||||
|
||||
//Assuming: 1
|
||||
@IggyFieldType(value = DataType.uint8_t)
|
||||
private int platform1;
|
||||
|
||||
//32/64
|
||||
@IggyFieldType(value = DataType.uint8_t)
|
||||
private int platform2;
|
||||
|
||||
//Assuming: 1
|
||||
@IggyFieldType(value = DataType.uint8_t)
|
||||
private int platform3;
|
||||
|
||||
//Usually: 3
|
||||
@IggyFieldType(value = DataType.uint8_t)
|
||||
private int platform4;
|
||||
|
||||
//flags for platform 64?
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
private long unk_0C;
|
||||
|
||||
@IggyArrayFieldType(value = DataType.uint8_t, count = 12)
|
||||
private byte[] reserved;
|
||||
|
||||
@IggyFieldType(value = DataType.uint32_t)
|
||||
private long numSubfiles;
|
||||
|
||||
public IggyHeader(AbstractDataStream stream) throws IOException {
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param version
|
||||
* @param platform1
|
||||
* @param platform2 32/64
|
||||
* @param platform3
|
||||
* @param platform4
|
||||
* @param unk_0C
|
||||
* @param reserved
|
||||
* @param num_subfiles
|
||||
*/
|
||||
public IggyHeader(long version, int platform1, int platform2, int platform3, int platform4, long unk_0C, byte[] reserved, long num_subfiles) {
|
||||
this.version = version;
|
||||
this.platform1 = platform1;
|
||||
this.platform2 = platform2;
|
||||
this.platform3 = platform3;
|
||||
this.platform4 = platform4;
|
||||
this.unk_0C = unk_0C;
|
||||
this.reserved = reserved;
|
||||
this.numSubfiles = num_subfiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
sb.append("version: ").append(version).append(", ");
|
||||
sb.append("platform: ").append(platform1).append(" ").append(platform2).append(" ").append(platform3).append(" ").append(platform4).append(", ");
|
||||
sb.append("unk_0C: ").append(String.format("%08X", unk_0C)).append(", ");
|
||||
sb.append("reserved: 12 bytes").append(", ");
|
||||
sb.append("num_subfiles: ").append(numSubfiles);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
magic = stream.readUI32();
|
||||
if (magic != IggyHeader.MAGIC) {
|
||||
throw new IOException("Invalid Iggy file");
|
||||
}
|
||||
version = stream.readUI32();
|
||||
platform1 = stream.readUI8();
|
||||
platform2 = stream.readUI8(); //32/64
|
||||
platform3 = stream.readUI8();
|
||||
platform4 = stream.readUI8();
|
||||
unk_0C = stream.readUI32();
|
||||
reserved = stream.readBytes(12);
|
||||
numSubfiles = stream.readUI32();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public boolean is64() {
|
||||
return platform2 == 64;
|
||||
}
|
||||
|
||||
public long getMagic() {
|
||||
return magic;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public int getPlatform1() {
|
||||
return platform1;
|
||||
}
|
||||
|
||||
public int getPlatform2() {
|
||||
return platform2;
|
||||
}
|
||||
|
||||
public int getPlatform3() {
|
||||
return platform3;
|
||||
}
|
||||
|
||||
public int getPlatform4() {
|
||||
return platform4;
|
||||
}
|
||||
|
||||
public long getUnk_0C() {
|
||||
return unk_0C;
|
||||
}
|
||||
|
||||
public byte[] getReserved() {
|
||||
return reserved;
|
||||
}
|
||||
|
||||
public long getNumSubfiles() {
|
||||
return numSubfiles;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jindra
|
||||
*/
|
||||
public class IggyIndexParser {
|
||||
|
||||
private static Logger LOGGER = Logger.getLogger(IggyIndexParser.class.getName());
|
||||
|
||||
/*
|
||||
Offsets:
|
||||
1) name
|
||||
2) UI16 - zero
|
||||
3) tag list
|
||||
4) ... tag data offsets
|
||||
|
||||
*/
|
||||
/**
|
||||
* Parser for index data. It creates table of indices and table of offsets
|
||||
*
|
||||
* @param indexStream Stream of index
|
||||
* @param indexTableEntry Output index tabke
|
||||
* @param offsets Output list of offsets
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public static void parseIndex(ByteArrayDataStream indexStream, List<Integer> indexTableEntry, List<Long> offsets) throws IOException {
|
||||
int indexTableSize = indexStream.readUI8();
|
||||
int[] indexTable = new int[indexTableSize];
|
||||
for (int i = 0; i < indexTableSize; i++) {
|
||||
int offset = indexStream.readUI8();
|
||||
LOGGER.fine(String.format("index_table_entry: %02x\n", offset));
|
||||
indexTable[i] = offset;
|
||||
indexTableEntry.add(offset);
|
||||
int num = indexStream.readUI8();
|
||||
indexStream.seek(num * 2, SeekMode.CUR);
|
||||
}
|
||||
|
||||
long offset = 0;
|
||||
int code;
|
||||
|
||||
while ((code = indexStream.readUI8()) > -1) {
|
||||
LOGGER.finer(String.format("Code = %x\n", code));
|
||||
|
||||
if (code < 0x80) // 0-0x7F
|
||||
{
|
||||
// code is directly an index to the index_table
|
||||
if (code >= indexTableSize) {
|
||||
LOGGER.severe(String.format("< 0x80: index is greater than index_table_size. %x > %x\n", code, indexTableSize));
|
||||
return;
|
||||
}
|
||||
|
||||
offset += indexTable[code];
|
||||
} else if (code < 0xC0) // 0x80-BF
|
||||
{
|
||||
int index;
|
||||
|
||||
if ((index = indexStream.readUI8()) < 0) {
|
||||
LOGGER.severe(String.format("< 0xC0: Cannot read index.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (index >= indexTableSize) {
|
||||
LOGGER.severe(String.format("< 0xC0: index is greater than index_table_size. %x > %x\n", index, indexTableSize));
|
||||
return;
|
||||
}
|
||||
|
||||
int n = code - 0x7F;
|
||||
offset += indexTable[index] * n;
|
||||
} else if (code < 0xD0) // 0xC0-0xCF
|
||||
{
|
||||
offset += ((code * 2) - 0x17E);
|
||||
} else if (code < 0xE0) // 0xD0-0xDF
|
||||
{
|
||||
// Code here depends on plattform[0], we are assuming it is 1, as we checked in load function
|
||||
int i = code & 0xF;
|
||||
int n8;
|
||||
int n;
|
||||
|
||||
if ((n8 = indexStream.readUI8()) < 0) {
|
||||
LOGGER.severe(String.format("< 0xE0: Cannot read n.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
n = n8 + 1;
|
||||
|
||||
if (indexStream.is64()) {
|
||||
if (i <= 2) {
|
||||
offset += 8 * n; // Ptr type
|
||||
} else if (i <= 4) {
|
||||
offset += 2 * n;
|
||||
} else if (i == 5) {
|
||||
offset += 4 * n;
|
||||
} else if (i == 6) {
|
||||
offset += 8 * n; // 64 bits type
|
||||
} else {
|
||||
LOGGER.severe(String.format("< 0xE0: Invalid value for i (%x %x)\n", i, code));
|
||||
}
|
||||
} else {
|
||||
switch (i) {
|
||||
case 2:
|
||||
offset += 4 * n; // Ptr type
|
||||
break;
|
||||
case 4:
|
||||
offset += 2 * n;
|
||||
break;
|
||||
case 5:
|
||||
offset += 4 * n; // 32 bits type
|
||||
break;
|
||||
case 6:
|
||||
offset += 8 * n;
|
||||
break;
|
||||
default:
|
||||
LOGGER.severe(String.format("< 0xE0: invalid value for i (%x %x)\n", i, code));
|
||||
}
|
||||
}
|
||||
} else if (code == 0xFC) {
|
||||
indexStream.seek(1, SeekMode.CUR);
|
||||
} else if (code == 0xFD) {
|
||||
int n, m;
|
||||
|
||||
if ((n = indexStream.readUI8()) < 0) {
|
||||
LOGGER.severe(String.format("0xFD: Cannot read n.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m = indexStream.readUI8()) < 0) {
|
||||
LOGGER.severe(String.format("0xFD: Cannot read m.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
indexStream.seek(m * 2, SeekMode.CUR);
|
||||
} else if (code == 0xFE) {
|
||||
int n8;
|
||||
int n;
|
||||
|
||||
if ((n8 = indexStream.readUI8()) < 0) {
|
||||
LOGGER.severe(String.format("0xFE: Cannot read n.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
n = n8 + 1;
|
||||
offset += n;
|
||||
} else if (code == 0xFF) {
|
||||
long n;
|
||||
|
||||
if ((n = indexStream.readUI32()) < 0) {
|
||||
LOGGER.severe(String.format("0xFF: Cannot read n.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
} else {
|
||||
LOGGER.warning(String.format("Unrecognized code: %x\n", code));
|
||||
}
|
||||
|
||||
offsets.add(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyShape implements StructureInterface {
|
||||
|
||||
private static Logger LOGGER = Logger.getLogger(IggyShape.class.getName());
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float minx; //bearing X - this is the horizontal distance from the current pen position to the glyph's left bbox edge.
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float miny; //bearing Y - this is the vertical distance from the baseline to the top of the glyph's bbox.
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float maxx; //advanceX - bearingX
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float maxy; //advanceY - bearingY
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long unk; // stejny vetsinou - napr. 48 - JP: to by mohlo byt advance
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long count;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long one; // 1
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long one2; // 1
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long one3; // 1
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long one4; // 1
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long two1; // 2
|
||||
|
||||
public float getBearingX() {
|
||||
return minx;
|
||||
}
|
||||
|
||||
public float getBearingY() {
|
||||
return miny;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return maxx - minx;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return maxy - miny;
|
||||
}
|
||||
|
||||
List<IggyShapeNode> nodes;
|
||||
|
||||
private long offset;
|
||||
|
||||
public IggyShape(AbstractDataStream stream, long offset) throws IOException {
|
||||
this.offset = offset;
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
public IggyShape(float minx, float miny, float maxx, float maxy, long advance, long count, long one, long one2, long one3, long one4, long two1, List<IggyShapeNode> nodes) {
|
||||
this.minx = minx;
|
||||
this.miny = miny;
|
||||
this.maxx = maxx;
|
||||
this.maxy = maxy;
|
||||
this.unk = advance;
|
||||
this.count = count;
|
||||
this.one = one;
|
||||
this.one2 = one2;
|
||||
this.one3 = one3;
|
||||
this.one4 = one4;
|
||||
this.two1 = two1;
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream s) throws IOException {
|
||||
s.seek(offset, SeekMode.SET);
|
||||
minx = s.readFloat();
|
||||
miny = s.readFloat();
|
||||
maxx = s.readFloat();
|
||||
maxy = s.readFloat();
|
||||
unk = s.readUI64();
|
||||
count = s.readUI64();
|
||||
one = s.readUI64();
|
||||
one2 = s.readUI64();
|
||||
one3 = s.readUI64();
|
||||
one4 = s.readUI32();
|
||||
two1 = s.readUI32();
|
||||
|
||||
if ((one != 1) || (one2 != 1) || (one3 != 1) || (one4 != 1) || (two1 != 2)) {
|
||||
LOGGER.fine(String.format("Unique header at pos %d, one: %d, one2: %d, one3: %d, one4: %d, two1: %d\n", offset, one, one2, one3, one4, two1));
|
||||
}
|
||||
|
||||
nodes = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
nodes.add(new IggyShapeNode(s, i == 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public float getMinx() {
|
||||
return minx;
|
||||
}
|
||||
|
||||
public float getMiny() {
|
||||
return miny;
|
||||
}
|
||||
|
||||
public float getMaxx() {
|
||||
return maxx;
|
||||
}
|
||||
|
||||
public float getMaxy() {
|
||||
return maxy;
|
||||
}
|
||||
|
||||
public long getUnk() {
|
||||
return unk;
|
||||
}
|
||||
|
||||
public long getOne() {
|
||||
return one;
|
||||
}
|
||||
|
||||
public long getOne2() {
|
||||
return one2;
|
||||
}
|
||||
|
||||
public long getOne3() {
|
||||
return one3;
|
||||
}
|
||||
|
||||
public long getOne4() {
|
||||
return one4;
|
||||
}
|
||||
|
||||
public long getTwo1() {
|
||||
return two1;
|
||||
}
|
||||
|
||||
public List<IggyShapeNode> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyShapeNode implements StructureInterface {
|
||||
|
||||
private static Logger LOGGER = Logger.getLogger(IggyShapeNode.class.getName());
|
||||
|
||||
public static int NODE_TYPE_MOVE = 1;
|
||||
public static int NODE_TYPE_LINE_TO = 2;
|
||||
public static int NODE_TYPE_CURVE_POINT = 3;
|
||||
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float targetX;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float targetY; // negative
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float controlX; // for curves
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float controlY; // for curves, negative
|
||||
@IggyFieldType(DataType.uint8_t) //1-moveto, 2-lineto , 3 - curve to
|
||||
int node_type;
|
||||
@IggyFieldType(DataType.uint8_t) // 208 start smooth (for j=1 only), 61 smooth interupt (muze a nemusi byt pro novy oddeleny kus charu - kdyz je subtype predchoziho vetsi nez 0 (kupr 5) bude pro oddeleny usek 61, jinak pokud je subtype predchoziho 0 bude pro oddeleny usek 0)
|
||||
int node_subtype;
|
||||
@IggyFieldType(DataType.uint8_t)
|
||||
int zer1;
|
||||
@IggyFieldType(DataType.uint8_t)
|
||||
int zer2;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long isstart; // 1 v prubehu nebo 0 pouze pro prvni (i kdyz jsou delene jako dvojtecka!!!)
|
||||
|
||||
private boolean first;
|
||||
|
||||
public IggyShapeNode(float x1, float y1, float x2, float y2, int node_type, int node_subtype, int zer1, int zer2, long isstart) {
|
||||
this.targetX = x1;
|
||||
this.targetY = y1;
|
||||
this.controlX = x2;
|
||||
this.controlY = y2;
|
||||
this.node_type = node_type;
|
||||
this.node_subtype = node_subtype;
|
||||
this.zer1 = zer1;
|
||||
this.zer2 = zer2;
|
||||
this.isstart = isstart;
|
||||
}
|
||||
|
||||
public IggyShapeNode(AbstractDataStream s, boolean first) throws IOException {
|
||||
this.first = first;
|
||||
readFromDataStream(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream s) throws IOException {
|
||||
targetX = s.readFloat();
|
||||
targetY = s.readFloat();
|
||||
controlX = s.readFloat();
|
||||
controlY = s.readFloat();
|
||||
node_type = s.readUI8();
|
||||
node_subtype = s.readUI8();
|
||||
zer1 = s.readUI8();
|
||||
zer2 = s.readUI8();
|
||||
isstart = s.readUI32();
|
||||
|
||||
if ((zer1 != 0) | (zer2 != 0)) {
|
||||
LOGGER.fine(String.format("Unknown zeroes at pos %08X\n", s.position() - 6));
|
||||
}
|
||||
if ((!first) & (isstart != 1)) {
|
||||
LOGGER.fine(String.format("Unknown format at pos %08X\n", s.position() - 4));
|
||||
}
|
||||
if ((first) & (isstart != 0)) {
|
||||
LOGGER.fine(String.format("Unknown format at pos %08X\n", s.position() - 4));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public float getX1() {
|
||||
return targetX;
|
||||
}
|
||||
|
||||
public float getY1() {
|
||||
return targetY;
|
||||
}
|
||||
|
||||
public float getX2() {
|
||||
return controlX;
|
||||
}
|
||||
|
||||
public float getY2() {
|
||||
return controlY;
|
||||
}
|
||||
|
||||
public int getNodeType() {
|
||||
return node_type;
|
||||
}
|
||||
|
||||
public int getNodeSubType() {
|
||||
return node_subtype;
|
||||
}
|
||||
|
||||
public int getZer1() {
|
||||
return zer1;
|
||||
}
|
||||
|
||||
public int getZer2() {
|
||||
return zer2;
|
||||
}
|
||||
|
||||
public boolean isStart() {
|
||||
return isstart == 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*
|
||||
* Based of works of somebody called eternity.
|
||||
*/
|
||||
public class IggySubFileEntry implements StructureInterface {
|
||||
|
||||
public static final int TYPE_INDEX = 0;
|
||||
public static final int TYPE_FLASH = 1;
|
||||
|
||||
@SWFType(BasicType.UI32)
|
||||
long type;
|
||||
|
||||
@SWFType(BasicType.UI32)
|
||||
long size;
|
||||
|
||||
//apparently same as size, maybe (un)compressed (?)
|
||||
@SWFType(BasicType.UI32)
|
||||
long size2;
|
||||
|
||||
//absolute offset
|
||||
@SWFType(BasicType.UI32)
|
||||
long offset;
|
||||
|
||||
public IggySubFileEntry(AbstractDataStream stream) throws IOException {
|
||||
readFromDataStream(stream);
|
||||
}
|
||||
|
||||
public IggySubFileEntry(long type, long size, long size2, long offset) {
|
||||
this.type = type;
|
||||
this.size = size;
|
||||
this.size2 = size2;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
sb.append("id: ").append(type).append(", ");
|
||||
sb.append("size: ").append(size).append(", ");
|
||||
sb.append("size2: ").append(size2).append(", ");
|
||||
sb.append("offset: ").append(offset);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException {
|
||||
type = stream.readUI32();
|
||||
size = stream.readUI32();
|
||||
size2 = stream.readUI32();
|
||||
offset = stream.readUI32();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyText implements StructureInterface {
|
||||
|
||||
public static final int ID = 0xFF06;
|
||||
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int type; // Tag type
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int textIndex;
|
||||
@IggyArrayFieldType(value = DataType.uint8_t, count = 28)
|
||||
byte zeroone[];
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float par1;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float par2;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float par3;
|
||||
@IggyFieldType(DataType.float_t)
|
||||
float par4;
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int enum_hex;
|
||||
|
||||
//Guessed
|
||||
boolean hasText;
|
||||
boolean wordWrap;
|
||||
boolean multiline;
|
||||
boolean password;
|
||||
boolean readOnly;
|
||||
boolean hasTextColor;
|
||||
boolean hasMaxLength;
|
||||
boolean hasFont;
|
||||
boolean hasFontClass;
|
||||
boolean autosize;
|
||||
boolean hasLayout;
|
||||
boolean noSelect;
|
||||
boolean border;
|
||||
boolean wasStatic;
|
||||
boolean html;
|
||||
boolean useOutlines;
|
||||
|
||||
@IggyFieldType(DataType.uint16_t)
|
||||
int fontIndex;
|
||||
@IggyFieldType(DataType.uint32_t)
|
||||
long zero;
|
||||
@IggyFieldType(DataType.uint64_t)
|
||||
long one;
|
||||
@IggyArrayFieldType(value = DataType.uint8_t, count = 32)
|
||||
byte[] some; // same for different fonts
|
||||
@IggyArrayFieldType(value = DataType.widechar_t)
|
||||
String initialText; //till end of info file?
|
||||
|
||||
public IggyText(int type, int order_in_iggy_file, byte[] zeroone, float par1, float par2, float par3, float par4, int enum_hex, int for_which_font_order_in_iggyfile, long zero, long one, byte[] some, long offset_of_name, String name) {
|
||||
this.type = type;
|
||||
this.textIndex = order_in_iggy_file;
|
||||
this.zeroone = zeroone;
|
||||
this.par1 = par1;
|
||||
this.par2 = par2;
|
||||
this.par3 = par3;
|
||||
this.par4 = par4;
|
||||
this.enum_hex = enum_hex;
|
||||
this.fontIndex = for_which_font_order_in_iggyfile;
|
||||
this.zero = zero;
|
||||
this.one = one;
|
||||
this.some = some;
|
||||
this.initialText = name;
|
||||
}
|
||||
|
||||
public IggyText(AbstractDataStream stream) throws IOException {
|
||||
this.readFromDataStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromDataStream(AbstractDataStream s) throws IOException {
|
||||
|
||||
type = s.readUI16();
|
||||
//characterId - iggy Id
|
||||
textIndex = s.readUI16();
|
||||
zeroone = s.readBytes(28);
|
||||
|
||||
//bounds?:
|
||||
par1 = s.readFloat();
|
||||
par2 = s.readFloat();
|
||||
par3 = s.readFloat();
|
||||
par4 = s.readFloat();
|
||||
|
||||
//flags
|
||||
enum_hex = s.readUI16();
|
||||
|
||||
int en = enum_hex;
|
||||
|
||||
//guessing - it could be like DefineEditText?...
|
||||
hasText = ((en >> 0) & 1) == 1;
|
||||
wordWrap = ((en >> 1) & 1) == 1;
|
||||
multiline = ((en >> 2) & 1) == 1;
|
||||
password = ((en >> 3) & 1) == 1;
|
||||
readOnly = ((en >> 4) & 1) == 1;
|
||||
hasTextColor = ((en >> 5) & 1) == 1;
|
||||
hasMaxLength = ((en >> 6) & 1) == 1;
|
||||
hasFont = ((en >> 7) & 1) == 1;
|
||||
hasFontClass = ((en >> 8) & 1) == 1;
|
||||
autosize = ((en >> 9) & 1) == 1;
|
||||
hasLayout = ((en >> 10) & 1) == 1;
|
||||
noSelect = ((en >> 11) & 1) == 1;
|
||||
border = ((en >> 12) & 1) == 1;
|
||||
wasStatic = ((en >> 13) & 1) == 1;
|
||||
html = ((en >> 14) & 1) == 1;
|
||||
useOutlines = ((en >> 15) & 1) == 1;
|
||||
|
||||
//if hasFont?
|
||||
fontIndex = s.readUI16(); //fontId
|
||||
//if hasFontClass - readString?
|
||||
//if hasFont || hasFontClass - readFontHeight?
|
||||
//if hasTextColor....?
|
||||
zero = s.readUI32();
|
||||
one = s.readUI64(); //01CB FF33 3333
|
||||
some = s.readBytes(32); // [6] => 40, [24] => 8
|
||||
StringBuilder textBuilder = new StringBuilder();
|
||||
do {
|
||||
char c = (char) s.readUI16();
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
textBuilder.append(c);
|
||||
} while (true);
|
||||
initialText = textBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getTextIndex() {
|
||||
return textIndex;
|
||||
}
|
||||
|
||||
public byte[] getZeroone() {
|
||||
return zeroone;
|
||||
}
|
||||
|
||||
public float getPar1() {
|
||||
return par1;
|
||||
}
|
||||
|
||||
public float getPar2() {
|
||||
return par2;
|
||||
}
|
||||
|
||||
public float getPar3() {
|
||||
return par3;
|
||||
}
|
||||
|
||||
public float getPar4() {
|
||||
return par4;
|
||||
}
|
||||
|
||||
public int getEnum_hex() {
|
||||
return enum_hex;
|
||||
}
|
||||
|
||||
public int getFontIndex() {
|
||||
return fontIndex;
|
||||
}
|
||||
|
||||
public long getZero() {
|
||||
return zero;
|
||||
}
|
||||
|
||||
public long getOne() {
|
||||
return one;
|
||||
}
|
||||
|
||||
public byte[] getSome() {
|
||||
return some;
|
||||
}
|
||||
|
||||
public String getInitialText() {
|
||||
return initialText;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jindra
|
||||
*/
|
||||
public enum SeekMode {
|
||||
SET, CUR, END
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.jpexs.decompiler.flash.iggy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface StructureInterface {
|
||||
|
||||
public void readFromDataStream(AbstractDataStream stream) throws IOException;
|
||||
|
||||
public void writeToDataStream(AbstractDataStream stream) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.jpexs.decompiler.flash.iggy.annotations;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.DataType;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author JPEXS
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface IggyArrayFieldType {
|
||||
|
||||
/// Type of value
|
||||
DataType value() default DataType.unknown;
|
||||
|
||||
int count() default -1;
|
||||
|
||||
/// Field name on which Count depends
|
||||
String countField() default "";
|
||||
|
||||
//Count to add to countField
|
||||
int countAdd() default 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.jpexs.decompiler.flash.iggy.annotations;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.DataType;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface IggyFieldType {
|
||||
|
||||
/// Type of value
|
||||
DataType value() default DataType.unknown;
|
||||
|
||||
/// Alternate type when condition is met
|
||||
DataType alternateValue() default DataType.unknown;
|
||||
|
||||
/// Condition for alternate type
|
||||
String alternateCondition() default "";
|
||||
|
||||
/// Count - used primarily for bit fields UB,SB,FB to specify number of bits
|
||||
int count() default -1;
|
||||
|
||||
/// Field name on which Count depends
|
||||
String countField() default "";
|
||||
|
||||
//Count to add to countField
|
||||
int countAdd() default 0;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.jpexs.decompiler.flash.iggy.conversion;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyShape;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyShapeNode;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyShapeToSwfConvertor {
|
||||
|
||||
private static int makeLengthsEmX(double val) {
|
||||
return (int) (val * 1024.0);
|
||||
}
|
||||
|
||||
private static int makeLengthsEmY(double val) {
|
||||
return (int) (val * 1024.0);
|
||||
}
|
||||
|
||||
public static SHAPE convertCharToShape(IggyShape igchar) {
|
||||
SHAPE shape = new SHAPE();
|
||||
List<SHAPERECORD> retList = new ArrayList<>();
|
||||
List<IggyShapeNode> ignodes = igchar.getNodes();
|
||||
|
||||
int prevX = 0;
|
||||
int prevY = 0;
|
||||
|
||||
for (IggyShapeNode ign : ignodes) {
|
||||
if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_MOVE) {
|
||||
StyleChangeRecord scr = new StyleChangeRecord();
|
||||
scr.stateMoveTo = true;
|
||||
prevX = scr.moveDeltaX = makeLengthsEmX(ign.getX1());
|
||||
prevY = scr.moveDeltaY = makeLengthsEmY(ign.getY1());
|
||||
scr.fillStyles = new FILLSTYLEARRAY();
|
||||
scr.lineStyles = new LINESTYLEARRAY();
|
||||
scr.calculateBits();
|
||||
retList.add(scr);
|
||||
} else {
|
||||
|
||||
int curX1 = makeLengthsEmX(ign.getX1());
|
||||
int curY1 = makeLengthsEmY(ign.getY1());
|
||||
|
||||
int curX2 = makeLengthsEmX(ign.getX2());
|
||||
int curY2 = makeLengthsEmY(ign.getY2());
|
||||
|
||||
if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_LINE_TO) {
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.deltaX = curX1 - prevX;
|
||||
ser.deltaY = curY1 - prevY;
|
||||
ser.generalLineFlag = true;
|
||||
ser.simplify();
|
||||
ser.calculateBits();
|
||||
prevX = curX1;
|
||||
prevY = curY1;
|
||||
retList.add(ser);
|
||||
} else if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_CURVE_POINT) {
|
||||
CurvedEdgeRecord cer = new CurvedEdgeRecord();
|
||||
cer.controlDeltaX = curX2 - prevX;
|
||||
cer.controlDeltaY = curY2 - prevY;
|
||||
cer.anchorDeltaX = curX1 - curX2;
|
||||
cer.anchorDeltaY = curY1 - curY2;
|
||||
prevX = curX1;
|
||||
prevY = curY1;
|
||||
cer.calculateBits();
|
||||
retList.add(cer);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!retList.isEmpty()) {
|
||||
StyleChangeRecord init;
|
||||
if (retList.get(0) instanceof StyleChangeRecord) {
|
||||
init = (StyleChangeRecord) retList.get(0);
|
||||
} else {
|
||||
init = new StyleChangeRecord();
|
||||
retList.add(0, init);
|
||||
}
|
||||
init.stateFillStyle0 = true;
|
||||
init.fillStyle0 = 1;
|
||||
shape.numFillBits = 1;
|
||||
|
||||
} else {
|
||||
shape.numFillBits = 0;
|
||||
|
||||
}
|
||||
retList.add(new EndShapeRecord());
|
||||
shape.shapeRecords = retList;
|
||||
shape.numLineBits = 0;
|
||||
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
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.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.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 iggyFile.getSwfCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKeys() {
|
||||
Set<String> ret = new TreeSet<>();
|
||||
for (int i = 0; i < length(); i++) {
|
||||
ret.add(iggyFile.getSwfName(i));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private int keyToSwfIndex(String key) {
|
||||
for (int i = 0; i < length(); i++) {
|
||||
if (key.equals(iggyFile.getSwfName(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Key " + key + " does not exist!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableInputStream getSWF(String key) throws IOException {
|
||||
SWF swf = IggyToSwfConvertor.getSwf(iggyFile, keyToSwfIndex(key));
|
||||
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 true; //TODO: make writable
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putSWF(String key, InputStream is) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
package com.jpexs.decompiler.flash.iggy.conversion;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFCompression;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyShape;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyCharKerning;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyShapeNode;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyCharOffset;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyCharAdvances;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyFile;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyFont;
|
||||
import com.jpexs.decompiler.flash.iggy.IggyText;
|
||||
import com.jpexs.decompiler.flash.tags.DefineEditTextTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
|
||||
import com.jpexs.decompiler.flash.tags.EndTag;
|
||||
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* WIP
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IggyToSwfConvertor {
|
||||
|
||||
public static 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 static void exportAllSwfsToDir(IggyFile file, File outputDir) throws IOException {
|
||||
for (int swfIndex = 0; swfIndex < file.getSwfCount(); swfIndex++) {
|
||||
exportSwfToDir(file, swfIndex, outputDir);
|
||||
}
|
||||
}
|
||||
|
||||
public static 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 static void exportSwfToFile(IggyFile file, int swfIndex, File outputFile) throws IOException {
|
||||
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
|
||||
exportSwf(file, swfIndex, fos);
|
||||
}
|
||||
}
|
||||
|
||||
public static void exportSwf(IggyFile file, int swfIndex, OutputStream output) throws IOException {
|
||||
SWF swf = getSwf(file, swfIndex);
|
||||
swf.saveTo(output);
|
||||
}
|
||||
|
||||
private static int makeLengthsTwip(double val) {
|
||||
return (int) (val * SWF.unitDivisor);
|
||||
}
|
||||
|
||||
private static int makeLengthsEm(double val) {
|
||||
return (int) (val * 1024.0);
|
||||
}
|
||||
|
||||
private static SHAPE createEmptyChar() {
|
||||
SHAPE shape = new SHAPE();
|
||||
List<SHAPERECORD> retList = new ArrayList<>();
|
||||
|
||||
{
|
||||
StyleChangeRecord scr = new StyleChangeRecord();
|
||||
scr.stateMoveTo = true;
|
||||
scr.moveDeltaX = 0;
|
||||
scr.moveDeltaY = 0;
|
||||
scr.fillStyles = new FILLSTYLEARRAY();
|
||||
scr.lineStyles = new LINESTYLEARRAY();
|
||||
scr.calculateBits();
|
||||
retList.add(scr);
|
||||
}
|
||||
|
||||
/*{
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.deltaX = 1024;
|
||||
ser.deltaY = 0;
|
||||
ser.generalLineFlag = true;
|
||||
ser.simplify();
|
||||
ser.calculateBits();
|
||||
retList.add(ser);
|
||||
}
|
||||
|
||||
{
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.deltaX = 0;
|
||||
ser.deltaY = -1024;
|
||||
ser.generalLineFlag = true;
|
||||
ser.simplify();
|
||||
ser.calculateBits();
|
||||
retList.add(ser);
|
||||
}
|
||||
|
||||
{
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.deltaX = -1024;
|
||||
ser.deltaY = 0;
|
||||
ser.generalLineFlag = true;
|
||||
ser.simplify();
|
||||
ser.calculateBits();
|
||||
retList.add(ser);
|
||||
}
|
||||
|
||||
{
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.deltaX = 0;
|
||||
ser.deltaY = 1024;
|
||||
ser.generalLineFlag = true;
|
||||
ser.simplify();
|
||||
ser.calculateBits();
|
||||
retList.add(ser);
|
||||
}*/
|
||||
StyleChangeRecord init;
|
||||
if (!retList.isEmpty() && retList.get(0) instanceof StyleChangeRecord) {
|
||||
init = (StyleChangeRecord) retList.get(0);
|
||||
} else {
|
||||
init = new StyleChangeRecord();
|
||||
retList.add(0, init);
|
||||
}
|
||||
|
||||
retList.add(new EndShapeRecord());
|
||||
init.stateFillStyle1 = true;
|
||||
init.fillStyle1 = 1;
|
||||
shape.shapeRecords = retList;
|
||||
shape.numFillBits = 1;
|
||||
shape.numLineBits = 0;
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
public static SWF getSwf(IggyFile file, int swfIndex) {
|
||||
SWF swf = new SWF();
|
||||
swf.compression = SWFCompression.NONE;
|
||||
swf.frameCount = 1; //FIXME!!
|
||||
swf.frameRate = file.getSwfFrameRate(swfIndex);
|
||||
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 = 10; //FIXME
|
||||
|
||||
FileAttributesTag fat = new FileAttributesTag(swf);
|
||||
fat.actionScript3 = false;
|
||||
fat.hasMetadata = false;
|
||||
fat.useNetwork = false;
|
||||
swf.addTag(fat);
|
||||
|
||||
Set<Integer> fontIndices = file.getFontIds(swfIndex);
|
||||
|
||||
int currentCharId = 0;
|
||||
Map<Integer, Integer> fontIndex2CharId = new HashMap<>();
|
||||
|
||||
for (int fontIndex : fontIndices) {
|
||||
IggyFont iggyFont = file.getFont(swfIndex, fontIndex);
|
||||
DefineFont2Tag fontTag = new DefineFont2Tag(swf);
|
||||
currentCharId++;
|
||||
fontIndex2CharId.put(fontIndex, currentCharId);
|
||||
fontTag.fontID = currentCharId;
|
||||
/*System.out.println("===================");
|
||||
System.out.println("xscale: " + iggyFont.getXscale()); //80
|
||||
System.out.println("yscale: " + iggyFont.getYscale()); //19
|
||||
|
||||
System.out.println("unk_float1: " + iggyFont.getUnk_float()[0]);
|
||||
System.out.println("unk_float2: " + iggyFont.getUnk_float()[1]);
|
||||
System.out.println("unk_float3: " + iggyFont.getUnk_float()[2]);
|
||||
System.out.println("unk_float4: " + iggyFont.getUnk_float()[3]);
|
||||
System.out.println("unk_float5: " + iggyFont.getUnk_float()[4]);
|
||||
System.out.println("what_2: " + iggyFont.getWhat_2());
|
||||
System.out.println("what_3: " + iggyFont.getWhat_3());*/
|
||||
|
||||
fontTag.fontKerningTable = new ArrayList<>();
|
||||
IggyCharKerning ker = iggyFont.getCharKernings();
|
||||
if (ker != null) {
|
||||
for (int i = 0; i < ker.getKernCount(); i++) {
|
||||
int kerningCode1 = ker.getCharsA().get(i);
|
||||
int kerningCode2 = ker.getCharsA().get(i);
|
||||
int kerningOffset = ker.getKerningOffsets().get(i);
|
||||
fontTag.fontKerningTable.add(new KERNINGRECORD(kerningCode1, kerningCode2, kerningOffset));
|
||||
}
|
||||
}
|
||||
|
||||
fontTag.fontFlagsWideCodes = true;
|
||||
fontTag.fontFlagsWideOffsets = true;
|
||||
fontTag.fontAscent = iggyFont.getAscent();
|
||||
fontTag.fontDescent = iggyFont.getDescent();
|
||||
fontTag.fontLeading = iggyFont.getLeading();
|
||||
fontTag.codeTable = new ArrayList<>();
|
||||
fontTag.fontName = iggyFont.getName();
|
||||
fontTag.glyphShapeTable = new ArrayList<>();
|
||||
fontTag.fontBoundsTable = new ArrayList<>();
|
||||
fontTag.fontAdvanceTable = new ArrayList<>();
|
||||
fontTag.fontFlagsHasLayout = true;
|
||||
IggyCharAdvances advanceValues = iggyFont.getCharAdvances();
|
||||
for (int i = 0; i < iggyFont.getCharacterCount(); i++) {
|
||||
int code = iggyFont.getCharIndices().getChars().get(i);
|
||||
IggyShape glyph = iggyFont.getChars().get(i);
|
||||
fontTag.codeTable.add(code);
|
||||
SHAPE shp = IggyShapeToSwfConvertor.convertCharToShape(glyph);
|
||||
fontTag.glyphShapeTable.add(shp);
|
||||
fontTag.fontBoundsTable.add(shp.getBounds());
|
||||
fontTag.fontAdvanceTable.add(makeLengthsEm(advanceValues.getScales().get(i)));
|
||||
|
||||
}
|
||||
fontTag.setModified(true);
|
||||
swf.addTag(fontTag);
|
||||
}
|
||||
|
||||
/*
|
||||
//TODO: Texts, they are incomplete
|
||||
|
||||
Map<Integer, Integer> textIndex2CharId = new HashMap<>();
|
||||
|
||||
Set<Integer> textIds = file.getTextIds(swfIndex);
|
||||
for (int textId : textIds) {
|
||||
IggyText iggyText = file.getText(swfIndex, textId);
|
||||
DefineEditTextTag textTag = new DefineEditTextTag(swf);
|
||||
currentCharId++;
|
||||
textIndex2CharId.put(iggyText.getTextIndex(), currentCharId);
|
||||
textTag.characterID = currentCharId;
|
||||
textTag.hasText = true;
|
||||
textTag.initialText = iggyText.getInitialText();
|
||||
textTag.html = true;
|
||||
textTag.noSelect = true;
|
||||
textTag.wasStatic = true;
|
||||
textTag.hasFont = false;
|
||||
textTag.hasFontClass = false;
|
||||
textTag.hasMaxLength = false;
|
||||
//textTag.multiline = true;
|
||||
//textTag.wordWrap = true;
|
||||
//textTag.hasTextColor = true;
|
||||
//textTag.textColor = new RGBA(Color.black);
|
||||
//textTag.fontHeight = 40; //??
|
||||
textTag.readOnly = true;
|
||||
textTag.bounds = new RECT(
|
||||
makeLengthsTwip(iggyText.getPar3()),
|
||||
makeLengthsTwip(iggyText.getPar1()),
|
||||
makeLengthsTwip(iggyText.getPar4()),
|
||||
makeLengthsTwip(iggyText.getPar2())
|
||||
);
|
||||
|
||||
//textTag.hasFont = true;
|
||||
//textTag.fontId = fontIndex2CharId.get(iggyText.getFontIndex());
|
||||
textTag.setModified(true);
|
||||
swf.addTag(textTag);
|
||||
}
|
||||
*/
|
||||
swf.addTag(
|
||||
new EndTag(swf));
|
||||
swf.setModified(
|
||||
true);
|
||||
|
||||
return swf;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
if (args.length < 2 || (args[0].isEmpty() || args[1].isEmpty())) {
|
||||
System.err.println("Invalid arguments");
|
||||
System.err.println("Usage: iggy-extract.bat file.iggy d:/outdir/");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
File file = new File(args[0]);
|
||||
if (!file.exists()) {
|
||||
System.err.println("FAIL: Input file: " + file.getAbsolutePath() + " does not exist.");
|
||||
System.exit(1);
|
||||
}
|
||||
File outDir = new File(args[1]);
|
||||
if (!outDir.exists()) {
|
||||
if (!outDir.mkdirs()) {
|
||||
System.err.println("FAIL: Cannot create output directory");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
System.out.print("(1/2) Loading file " + args[0] + "...");
|
||||
IggyFile iggyFile = new IggyFile(new File(args[0]));
|
||||
System.out.println("OK");
|
||||
System.out.print("(2/2) Exporting SWF files to " + args[1] + "...");
|
||||
exportAllSwfsToDir(iggyFile, new File(args[1]));
|
||||
System.out.println("OK");
|
||||
System.out.println("All finished sucessfully.");
|
||||
System.exit(0);
|
||||
} catch (IOException ex) {
|
||||
System.out.println("FAIL");
|
||||
System.err.println("Error while converting: " + ex.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1271,7 +1271,7 @@ public class Main {
|
||||
|
||||
loadingDialog.setVisible(true);
|
||||
|
||||
for (int i = 0; i < sourceInfos.size(); i++) {
|
||||
for (int i = 0; i < newSourceInfos.length; i++) {
|
||||
SWFSourceInfo si = newSourceInfos[i];
|
||||
String fileName = si.getFile();
|
||||
if (fileName != null) {
|
||||
@@ -1434,7 +1434,7 @@ public class Main {
|
||||
}
|
||||
fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get()));
|
||||
FileFilter allSupportedFilter = new FileFilter() {
|
||||
private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"};
|
||||
private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip", ".iggy"};
|
||||
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
@@ -1493,6 +1493,19 @@ public class Main {
|
||||
};
|
||||
fc.addChoosableFileFilter(gfxFilter);
|
||||
|
||||
FileFilter iggyFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return (f.getName().toLowerCase().endsWith(".iggy")) || (f.isDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return AppStrings.translate("filter.iggy");
|
||||
}
|
||||
};
|
||||
fc.addChoosableFileFilter(iggyFilter);
|
||||
|
||||
FileFilter zipFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,53 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum TreeNodeType {
|
||||
|
||||
UNKNOWN,
|
||||
FLASH,
|
||||
FONT,
|
||||
TEXT,
|
||||
IMAGE,
|
||||
SHAPE,
|
||||
MORPH_SHAPE,
|
||||
SPRITE,
|
||||
BUTTON,
|
||||
AS,
|
||||
PACKAGE,
|
||||
FRAME,
|
||||
SHOW_FRAME,
|
||||
MOVIE,
|
||||
SOUND,
|
||||
BINARY_DATA,
|
||||
OTHER_TAG,
|
||||
FOLDER,
|
||||
FOLDER_OPEN,
|
||||
BUNDLE_ZIP,
|
||||
BUNDLE_SWC,
|
||||
BUNDLE_BINARY,
|
||||
HEADER,
|
||||
SET_BACKGROUNDCOLOR,
|
||||
FILE_ATTRIBUTES,
|
||||
METADATA,
|
||||
PLACE_OBJECT,
|
||||
REMOVE_OBJECT
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.gui;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum TreeNodeType {
|
||||
|
||||
UNKNOWN,
|
||||
FLASH,
|
||||
FONT,
|
||||
TEXT,
|
||||
IMAGE,
|
||||
SHAPE,
|
||||
MORPH_SHAPE,
|
||||
SPRITE,
|
||||
BUTTON,
|
||||
AS,
|
||||
PACKAGE,
|
||||
FRAME,
|
||||
SHOW_FRAME,
|
||||
MOVIE,
|
||||
SOUND,
|
||||
BINARY_DATA,
|
||||
OTHER_TAG,
|
||||
FOLDER,
|
||||
FOLDER_OPEN,
|
||||
BUNDLE_ZIP,
|
||||
BUNDLE_SWC,
|
||||
BUNDLE_BINARY,
|
||||
BUNDLE_IGGY,
|
||||
HEADER,
|
||||
SET_BACKGROUNDCOLOR,
|
||||
FILE_ATTRIBUTES,
|
||||
METADATA,
|
||||
PLACE_OBJECT,
|
||||
REMOVE_OBJECT
|
||||
}
|
||||
|
||||
BIN
src/com/jpexs/decompiler/flash/gui/graphics/bundleiggy16.png
Normal file
BIN
src/com/jpexs/decompiler/flash/gui/graphics/bundleiggy16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 879 B |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user