read/write abs adresses - WIP

This commit is contained in:
Jindra Petřík
2016-11-27 21:55:40 +01:00
parent 4dfcef525f
commit 398d12d9e9
12 changed files with 267 additions and 63 deletions

View File

@@ -82,6 +82,10 @@ public class IggyCharOffset implements StructureInterface {
}
}
public boolean hasGlyph() {
return offset > 0;
}
public long getZero() {
return zero;
}

View File

@@ -36,22 +36,79 @@ public class IggyFile implements StructureInterface {
private List<byte[]> subFileEntriesData = new ArrayList<>();
private List<IggyFlashHeaderInterface> headers = new ArrayList<>();
private List<IggySwf> flashDataReaders = new ArrayList<>();
private List<IggySwf> iggySwfs = new ArrayList<>();
private List<List<Integer>> indexTables = new ArrayList<>();
private List<List<Long>> offsetTables = new ArrayList<>();
private List<DataStreamInterface> indexDataStreams = new ArrayList<>();
public static final int FIRST_TAG_POSITION = 3;
public void replaceTag(int swfIndex, int tagIndex, IggyTag newTag) throws IOException {
WriteDataStreamInterface stream = new TemporaryDataStream();
newTag.writeToDataStream(stream);
setSwfItemLength(swfIndex, FIRST_TAG_POSITION + tagIndex, stream.totalSize());
}
public void saveTag(int swfIndex, IggyTag newTag) throws IOException {
WriteDataStreamInterface stream = new TemporaryDataStream();
newTag.writeToDataStream(stream);
int tagIndex = 0;
List<IggyTag> taglist = iggySwfs.get(swfIndex).getTags();
for (IggyTag t : taglist) {
if (t == newTag) {
break;
}
tagIndex++;
}
if (tagIndex < taglist.size()) {
setSwfItemLength(swfIndex, FIRST_TAG_POSITION + tagIndex, stream.totalSize());
} else {
throw new IllegalArgumentException("Tag does not exists in this iggy file");
}
}
private boolean setSwfItemLength(int swfIndex, int itemindex, long newLength) {
DataStreamInterface stream = indexDataStreams.get(swfIndex);
List<Long> offsetTable = offsetTables.get(swfIndex);
long offset = offsetTable.get(itemindex);
long nextOffset = itemindex == offsetTable.size() - 1 ? stream.totalSize() : offsetTable.get(itemindex + 1);
long currentSize = nextOffset - offset;
try {
byte indexData[] = stream.getAllBytes();
setItemLength(offset, header.is64(), indexData, newLength);
indexDataStreams.set(swfIndex, new TemporaryDataStream(indexData)); //TODO: optimize!
long lengthDelta = newLength - currentSize;
for (int i = itemindex + 1; i < offsetTable.size(); i++) {
offsetTable.set(i, offsetTable.get(i) + lengthDelta);
}
return true;
} catch (IOException ex) {
return false;
}
}
public IggySwf getSwf(int swfIndex) {
return iggySwfs.get(swfIndex);
}
public Set<Integer> getFontIds(int swfIndex) {
return flashDataReaders.get(swfIndex).fonts.keySet();
return iggySwfs.get(swfIndex).fonts.keySet();
}
public IggyFont getFont(int swfIndex, int fontId) {
return flashDataReaders.get(swfIndex).fonts.get(fontId);
return iggySwfs.get(swfIndex).fonts.get(fontId);
}
public IggyText getText(int swfIndex, int textId) {
return flashDataReaders.get(swfIndex).texts.get(textId);
return iggySwfs.get(swfIndex).texts.get(textId);
}
public Set<Integer> getTextIds(int swfIndex) {
return flashDataReaders.get(swfIndex).texts.keySet();
return iggySwfs.get(swfIndex).texts.keySet();
}
public IggyFile(String filePath) throws IOException {
@@ -144,6 +201,9 @@ public class IggyFile implements StructureInterface {
File inFile = new File(inFileName);
File outFile = new File(outFileName);
IggyFile iggyFile = new IggyFile(inFile);
IggySwf iswf = iggyFile.getSwf(0);
iggyFile.replaceSwf(0, iswf);
outFile.delete();
try (RandomAccessFileDataStream outputStream = new RandomAccessFileDataStream(outFile)) {
iggyFile.writeToDataStream(outputStream);
}
@@ -560,11 +620,11 @@ public class IggyFile implements StructureInterface {
}
public int getSwfCount() {
return flashDataReaders.size();
return iggySwfs.size();
}
public String getSwfName(int swfIndex) {
return flashDataReaders.get(swfIndex).getName();
return iggySwfs.get(swfIndex).getName();
}
public long getSwfXMin(int swfIndex) {
@@ -594,6 +654,7 @@ public class IggyFile implements StructureInterface {
}
byte replacementData[];
try (DataStreamInterface stream = new TemporaryDataStream()) {
headers.get(targetSwfIndex).writeToDataStream(stream);
iggySwf.writeToDataStream(stream);
replacementData = stream.getAllBytes();
} catch (IOException ex) {
@@ -611,6 +672,8 @@ public class IggyFile implements StructureInterface {
long oldSize = entry.size;
long newSize = replacementData.length;
offsetsChange = offsetsChange + (newSize - oldSize);
entry.size = newSize;
entry.size2 = newSize;
//entries after this one will have modified offsets
}
swfIndex++;
@@ -621,8 +684,6 @@ public class IggyFile implements StructureInterface {
}
private void parseEntries() throws IOException {
List<List<Integer>> indexTables = new ArrayList<>(); //TODO: use this for something ??
List<List<Long>> offsetTables = new ArrayList<>();
List<DataStreamInterface> flashDataStreams = new ArrayList<>();
for (int i = 0; i < subFileEntries.size(); i++) {
@@ -632,6 +693,7 @@ public class IggyFile implements StructureInterface {
List<Integer> indexTable = new ArrayList<>();
List<Long> offsets = new ArrayList<>();
IggyIndexParser.parseIndex(header.is64(), dataStream, indexTable, offsets);
indexDataStreams.add(dataStream);
indexTables.add(indexTable);
offsetTables.add(offsets);
} else if (entry.type == IggySubFileEntry.TYPE_FLASH) {
@@ -650,7 +712,7 @@ public class IggyFile implements StructureInterface {
for (int swfIndex = 0; swfIndex < headers.size(); swfIndex++) {
IggyFlashHeaderInterface hdr = headers.get(swfIndex);
IggySwf dataReader = new IggySwf((IggyFlashHeader64) hdr, flashDataStreams.get(swfIndex), offsetTables.get(swfIndex));
flashDataReaders.add(dataReader);
iggySwfs.add(dataReader);
}
}

View File

@@ -124,7 +124,37 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
@Override
public void writeToDataStream(WriteDataStreamInterface stream) throws IOException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
stream.writeUI64(main_offset);
stream.writeUI64(as3_section_offset);
stream.writeUI64(unk_offset);
stream.writeUI64(unk_offset2);
stream.writeUI64(unk_offset3);
stream.writeUI64(unk_offset4);
stream.writeUI32(xmin);
stream.writeUI32(ymin);
stream.writeUI32(xmax);
stream.writeUI32(ymax);
stream.writeUI32(unk_40);
stream.writeUI32(unk_44);
stream.writeUI32(unk_48);
stream.writeUI32(unk_4C);
stream.writeUI32(unk_50);
stream.writeUI32(unk_54);
stream.writeFloat(frame_rate);
stream.writeUI32(unk_5C);
stream.writeUI64(fonts_offset);
stream.writeUI64(unk_68);
stream.writeUI64(names_offset);
stream.writeUI64(unk_offset5);
stream.writeUI64(unk_80);
stream.writeUI64(last_section_offset);
stream.writeUI64(unk_offset6);
stream.writeUI64(as3_code_offset);
stream.writeUI64(as3_names_offset);
stream.writeUI32(unk_A8);
stream.writeUI32(unk_AC);
stream.writeUI32(font_count);
stream.writeUI32(unk_B4);
}
@Override

View File

@@ -176,9 +176,13 @@ public class IggyFont extends IggyTag {
}
}
private long makeAbsOffset(ReadDataStreamInterface s, long offset) {
return offset == 1 ? 0 : s.position() - 8 + offset;
}
@Override
public void readFromDataStream(ReadDataStreamInterface stream) throws IOException {
TemporaryDataStream s = new TemporaryDataStream(stream.readBytes((int) (long) stream.available()));
public void readFromDataStream(ReadDataStreamInterface s) throws IOException {
long basePos = s.position();
type = s.readUI16();
fontId = s.readUI16();
zeroone = s.readBytes(28);
@@ -187,19 +191,25 @@ public class IggyFont extends IggyTag {
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);
start_of_char_struct = s.readUI64();
long abs_start_of_char_struct = makeAbsOffset(s, start_of_char_struct);
start_of_char_index = s.readUI64();
long abs_start_of_char_index = makeAbsOffset(s, start_of_char_struct);
start_of_scale = s.readUI64();
long abs_start_of_scale = makeAbsOffset(s, start_of_char_struct);
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);
start_of_kern = s.readUI64();
long abs_start_of_kern = makeAbsOffset(s, start_of_kern);
zero_padd = s.readUI64();
what_2 = s.readUI64();
zero_padd_2 = s.readUI64();
start_of_name = readAbsoluteOffset(s);
start_of_name = s.readUI64();
long abs_start_of_name = makeAbsOffset(s, start_of_name);
one_padd = s.readUI64();
xscale = s.readUI16();
yscale = s.readUI16();
@@ -209,7 +219,7 @@ public class IggyFont extends IggyTag {
char_count = s.readUI32();
zero_padd_4 = s.readUI64();
what_3 = s.readUI64();
s.seek(272, SeekMode.CUR);
s.seek(basePos + 272, SeekMode.SET);
sss1 = s.readFloat();
one_padd2 = s.readUI32();
sss2 = s.readFloat();
@@ -218,8 +228,8 @@ public class IggyFont extends IggyTag {
one_padd4 = s.readUI32();
sss4 = s.readFloat();
one_padd5 = s.readUI32();
if (start_of_name != 0) {
s.seek(start_of_name, SeekMode.SET);
if (abs_start_of_name != 0) {
s.seek(abs_start_of_name, SeekMode.SET);
StringBuilder nameBuilder = new StringBuilder();
int nameCharCnt = 0;
do {
@@ -234,8 +244,8 @@ public class IggyFont extends IggyTag {
name = nameBuilder.toString();
}
s.readUI64(); //pad zero
if (start_of_char_struct != 0) {
s.seek(start_of_char_struct, SeekMode.SET);
if (abs_start_of_char_struct != 0) {
s.seek(abs_start_of_char_struct, SeekMode.SET);
charOffsets = new ArrayList<>();
for (int i = 0; i < char_count; i++) {
charOffsets.add(new IggyCharOffset(s));
@@ -243,19 +253,23 @@ public class IggyFont extends IggyTag {
glyphs = new ArrayList<>();
for (int i = 0; i < char_count; i++) {
long offset = charOffsets.get(i).offset;
glyphs.add(new IggyShape(s, offset));
if (offset != 0) {
glyphs.add(new IggyShape(s, offset));
} else {
glyphs.add(null);
}
}
}
if (start_of_char_index != 0) {
s.seek(start_of_char_index, SeekMode.SET);
if (abs_start_of_char_index != 0) {
s.seek(abs_start_of_char_index, SeekMode.SET);
codePoints = new IggyCharIndices(s, char_count);
}
if (start_of_scale != 0) {
s.seek(start_of_scale, SeekMode.SET);
if (abs_start_of_scale != 0) {
s.seek(abs_start_of_scale, SeekMode.SET);
charScales = new IggyCharAdvances(s, char_count);
}
if (start_of_kern != 0) {
s.seek(start_of_kern, SeekMode.SET);
if (abs_start_of_kern != 0) {
s.seek(abs_start_of_kern, SeekMode.SET);
charKernings = new IggyCharKerning(s, kern_count);
}
}
@@ -270,18 +284,23 @@ public class IggyFont extends IggyTag {
s.writeUI16(descent);
s.writeUI16(leading);
s.writeUI64(flags);
writeAbsoluteOffset(s, start_of_char_struct);
writeAbsoluteOffset(s, start_of_char_index);
writeAbsoluteOffset(s, start_of_scale);
long abs_start_of_char_struct = s.position() + start_of_char_struct;
s.writeUI64(start_of_char_struct);
long abs_start_of_char_index = s.position() + start_of_char_index;
s.writeUI64(start_of_char_index);
long abs_start_of_scale = s.position() + start_of_scale;
s.writeUI64(start_of_scale);
s.writeUI32(kern_count);
for (int i = 0; i < unk_float.length; i++) {
s.writeFloat(unk_float[i]);
}
writeAbsoluteOffset(s, start_of_kern);
long abs_start_of_kern = s.position() + start_of_kern;
s.writeUI64(start_of_kern);
s.writeUI64(zero_padd);
s.writeUI64(what_2);
s.writeUI64(zero_padd_2);
writeAbsoluteOffset(s, start_of_name);
long abs_start_of_name = s.position() + start_of_name;
s.writeUI64(start_of_name);
s.writeUI64(one_padd);
s.writeUI16(xscale);
s.writeUI16(yscale);
@@ -291,10 +310,7 @@ public class IggyFont extends IggyTag {
s.writeUI32(char_count);
s.writeUI64(zero_padd_4);
s.writeUI64(what_3);
//s.seek(272, SeekMode.CUR);
for (int i = 0; i < 272; i++) {
s.write(0);
}
s.seek(272, SeekMode.SET);
s.writeFloat(sss1);
s.writeUI32(one_padd2);
s.writeFloat(sss2);
@@ -303,7 +319,8 @@ public class IggyFont extends IggyTag {
s.writeUI32(one_padd4);
s.writeFloat(sss4);
s.writeUI32(one_padd5);
if (start_of_name != 0) {
if (abs_start_of_name != 0) {
s.seek(abs_start_of_name, SeekMode.SET);
for (char c : name.toCharArray()) {
s.writeUI16(c);
}
@@ -317,25 +334,33 @@ public class IggyFont extends IggyTag {
}
}
s.writeUI64(0); //pad zero
if (start_of_char_struct != 0) {
if (abs_start_of_char_struct != 0) {
s.seek(abs_start_of_char_struct, SeekMode.SET);
//offsets of shapes
for (IggyCharOffset ofs : charOffsets) {
ofs.writeToDataStream(s);
}
for (IggyShape shp : glyphs) {
shp.writeToDataStream(s);
for (int i = 0; i < glyphs.size(); i++) {
IggyShape shp = glyphs.get(i);
if (shp != null) {
s.seek(charOffsets.get(i).offset, SeekMode.SET);
shp.writeToDataStream(s);
}
}
}
if (start_of_char_index != 0) {
if (abs_start_of_char_index != 0) {
s.seek(abs_start_of_char_index, SeekMode.SET);
for (char c : codePoints.chars) {
s.writeUI16(c);
}
s.writeUI32(0);
}
if (start_of_scale != 0) {
if (abs_start_of_scale != 0) {
s.seek(abs_start_of_scale, SeekMode.SET);
charScales.writeToDataStream(s);
}
if (start_of_kern != 0) {
if (abs_start_of_kern != 0) {
s.seek(abs_start_of_kern, SeekMode.SET);
charKernings.writeToDataStream(s);
}
}
@@ -413,4 +438,9 @@ public class IggyFont extends IggyTag {
return ID;
}
@Override
public String toString() {
return String.format("IggyFontTag (%04X)", ID);
}
}

View File

@@ -62,7 +62,7 @@ public class IggyShape implements StructureInterface {
private long offset;
public IggyShape(AbstractDataStream stream, long offset) throws IOException {
public IggyShape(ReadDataStreamInterface stream, long offset) throws IOException {
this.offset = offset;
readFromDataStream(stream);
}

View File

@@ -6,7 +6,9 @@ import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface;
import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface;
import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType;
import com.jpexs.decompiler.flash.iggy.streams.DataStreamInterface;
import com.jpexs.decompiler.flash.iggy.streams.TemporaryDataStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -28,17 +30,26 @@ public class IggySwf implements StructureInterface {
private IggyFlashHeader64 header;
private Map<Long, Long> sizesOfOffsets;
private List<Long> allOffsets;
private List<Long> offsets;
private List<IggyTag> tags = new ArrayList<>();
public List<IggyTag> getTags() {
return tags;
}
public IggySwf(IggyFlashHeader64 header, ReadDataStreamInterface stream, List<Long> offsets) throws IOException {
this.header = header;
this.offsets = offsets;
calcSizesFromOffsets();
readFromDataStream(stream);
}
private void calcSizesFromOffsets() {
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
@@ -56,20 +67,25 @@ public class IggySwf implements StructureInterface {
//here is offset[1]
int pad8 = 8 - (int) (stream.position() % 8);
stream.seek(pad8, SeekMode.CUR);
//here is offset [2]
//here is offset [2]
fonts = new HashMap<>();
int fontIndex = 0;
for (int i = 2; i < allOffsets.size(); i++) {
long offset = allOffsets.get(i);
for (int ofs = 2; ofs < offsets.size(); ofs++) {
long offset = offsets.get(ofs);
if (offset < stream.position()) {
continue;
}
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
tags.add(font);
} else if (ofs < offsets.size() - 1) {
int len = (int) (offsets.get(ofs + 1) - offsets.get(ofs));
RawIggyPart rtag = new RawIggyPart(type, stream, len);
tags.add(rtag);
}
}
}
@@ -80,7 +96,29 @@ public class IggySwf implements StructureInterface {
@Override
public void writeToDataStream(WriteDataStreamInterface stream) throws IOException {
throw new UnsupportedOperationException("Not supported yet."); //TODO!!!
List<Long> newOffsets = new ArrayList<>();
try {
newOffsets.add(stream.position());
for (int i = 0; i < name.length(); i++) {
stream.writeUI16(name.charAt(i));
}
stream.writeUI16(0);
newOffsets.add(stream.position());
long pad8 = 8 - (stream.position() % 8);
for (int i = 0; i < pad8; i++) {
stream.write(0);
}
newOffsets.add(stream.position());
for (IggyTag tag : tags) {
tag.writeToDataStream(stream);
newOffsets.add(stream.position());
}
} catch (IOException ex) {
//ignore
}
this.offsets = newOffsets;
calcSizesFromOffsets();
}
@Override

View File

@@ -9,4 +9,9 @@ import com.jpexs.decompiler.flash.iggy.streams.StructureInterface;
public abstract class IggyTag implements StructureInterface {
public abstract int getTagType();
@Override
public String toString() {
return String.format("IggyTag (%04X)", getTagType());
}
}

View File

@@ -8,13 +8,13 @@ import java.io.IOException;
*
* @author JPEXS
*/
public class RawIggyTag extends IggyTag {
public class RawIggyPart extends IggyTag {
byte[] rawData;
int tagType;
private int length;
public RawIggyTag(int tagType, ReadDataStreamInterface stream, int length) throws IOException {
public RawIggyPart(int tagType, ReadDataStreamInterface stream, int length) throws IOException {
this.length = length;
this.tagType = tagType;
readFromDataStream(stream);

View File

@@ -150,11 +150,20 @@ public class IggyToSwfConvertor {
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);
IggyShape glyph = iggyFont.getChars().get(i);
SHAPE shp;
if (glyph != null) {
shp = IggyShapeToSwfConvertor.convertCharToShape(glyph);
fontTag.fontBoundsTable.add(shp.getBounds());
} else {
shp = new SHAPE();
shp.shapeRecords = new ArrayList<>();
shp.shapeRecords.add(new EndShapeRecord());
fontTag.fontBoundsTable.add(new RECT()); //??
}
fontTag.glyphShapeTable.add(shp);
fontTag.fontBoundsTable.add(shp.getBounds());
fontTag.fontAdvanceTable.add(makeLengthsEm(advanceValues.getScales().get(i)));
}

View File

@@ -5,6 +5,8 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
@@ -24,6 +26,15 @@ public class RandomAccessFileDataStream extends AbstractDataStream {
raf = new RandomAccessFile(file, "rw");
}
@Override
public Long totalSize() {
try {
return raf.length();
} catch (IOException ex) {
return null;
}
}
@Override
public Long available() {
try {
@@ -51,6 +62,13 @@ public class RandomAccessFileDataStream extends AbstractDataStream {
return val;
}
@Override
public byte[] readBytes(int numBytes) throws IOException {
byte buf[] = new byte[numBytes];
raf.readFully(buf);
return buf;
}
@Override
public void seek(long pos, SeekMode mode) throws IOException {
long newpos = pos;
@@ -60,7 +78,11 @@ public class RandomAccessFileDataStream extends AbstractDataStream {
newpos = raf.length() - pos;
}
if (newpos > raf.length()) {
throw new ArrayIndexOutOfBoundsException("Position outside bounds accessed: " + pos + ". Size: " + raf.length());
raf.seek(raf.length());
long curpos = raf.length();
for (long i = curpos; i < newpos; i++) {
raf.write(0);
}
} else if (newpos < 0) {
throw new ArrayIndexOutOfBoundsException("Negative position accessed: " + pos);
} else {

View File

@@ -15,6 +15,8 @@ public interface ReadDataStreamInterface extends AutoCloseable {
*/
public Long available();
public Long totalSize();
public long position();
public long readUI64() throws IOException;

View File

@@ -15,6 +15,8 @@ public interface WriteDataStreamInterface extends AutoCloseable {
*/
public Long available();
public Long totalSize();
public long position();
public boolean writeUI64(long val) throws IOException;