read/write fixes, refactorings

This commit is contained in:
Jindra Petřík
2016-11-28 19:16:13 +01:00
parent 29147348d6
commit f48a5ff08a
4 changed files with 131 additions and 98 deletions

View File

@@ -43,30 +43,29 @@ public class IggyFile implements StructureInterface {
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);
public void replaceFontTag(int targetSwfIndex, int fontIndex, IggyFont newFont) throws IOException {
IggySwf iggySwf = iggySwfs.get(targetSwfIndex);
iggySwf.replaceFontTag(fontIndex, newFont);
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;
DataStreamInterface flashStream = new TemporaryDataStream();
iggySwf.writeToDataStream(flashStream);
byte flashData[] = flashStream.getAllBytes();
int swfIndex = 0;
int offsetChange = 0;
for (int i = 0; i < subFileEntries.size(); i++) {
IggySubFileEntry entry = subFileEntries.get(i);
entry.offset += offsetChange;
if (entry.type == IggySubFileEntry.TYPE_FLASH) {
if (swfIndex == targetSwfIndex) {
long newLen = flashData.length;
long oldLen = entry.size;
offsetChange += (newLen - oldLen);
}
swfIndex++;
}
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");
}
subFileEntriesData.set(targetSwfIndex, flashData);
//TODO: Update index
}
private boolean setSwfItemLength(int swfIndex, int itemindex, long newLength) {
@@ -103,14 +102,6 @@ public class IggyFile implements StructureInterface {
return iggySwfs.get(swfIndex).fonts.get(fontId);
}
public IggyText getText(int swfIndex, int textId) {
return iggySwfs.get(swfIndex).texts.get(textId);
}
public Set<Integer> getTextIds(int swfIndex) {
return iggySwfs.get(swfIndex).texts.keySet();
}
public IggyFile(String filePath) throws IOException {
this(new File(filePath));
}
@@ -202,7 +193,8 @@ public class IggyFile implements StructureInterface {
File outFile = new File(outFileName);
IggyFile iggyFile = new IggyFile(inFile);
IggySwf iswf = iggyFile.getSwf(0);
iggyFile.replaceSwf(0, iswf);
IggyFont ifont = iswf.fonts.get(0);
iggyFile.replaceFontTag(0, 0, ifont);
outFile.delete();
try (RandomAccessFileDataStream outputStream = new RandomAccessFileDataStream(outFile)) {
iggyFile.writeToDataStream(outputStream);
@@ -649,7 +641,9 @@ public class IggyFile implements StructureInterface {
//WIP
public boolean replaceSwf(int targetSwfIndex, IggySwf iggySwf) {
if (targetSwfIndex < 0 || targetSwfIndex >= getSwfCount()) {
return false; //Not working yet - need to make IggySWF.writeToDataStream work
/*if (targetSwfIndex < 0 || targetSwfIndex >= getSwfCount()) {
throw new ArrayIndexOutOfBoundsException("No such SWF file index");
}
byte replacementData[];
@@ -680,7 +674,7 @@ public class IggyFile implements StructureInterface {
}
}
subFileEntriesData.set(targetSwfIndex, replacementData);
return true;
return true;*/
}
private void parseEntries() throws IOException {
@@ -697,23 +691,9 @@ public class IggyFile implements StructureInterface {
indexTables.add(indexTable);
offsetTables.add(offsets);
} else if (entry.type == IggySubFileEntry.TYPE_FLASH) {
IggyFlashHeaderInterface hdr;
if (header.is64()) {
hdr = new IggyFlashHeader64(dataStream);
} else {
hdr = new IggyFlashHeader32(dataStream);
throw new UnsupportedOperationException("Iggy 32bit files are not supported"); //TODO
}
headers.add(hdr);
flashDataStreams.add(dataStream);
iggySwfs.add(new IggySwf(dataStream));
}
}
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));
iggySwfs.add(dataReader);
}
}
@Override

View File

@@ -64,7 +64,7 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
@IggyFieldType(DataType.uint64_t)
long off_names; // 0x70 relative offset to the names/import section of the file - end of fonts
@IggyFieldType(DataType.uint64_t)
long off_unk8C; // 0x78 relative offset to something
long off_unk78; // 0x78 relative offset to something
@IggyFieldType(DataType.uint64_t)
long off_unk80;
@IggyFieldType(DataType.uint64_t)
@@ -97,13 +97,35 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
private long font_end_address;
private long sequence_start_address;
private long names_address;
private long unk8C_address;
private long unk78_address;
private long unk80_address;
private long last_section_address;
private long flash_filename_address;
private long decl_strings_address;
private long type_fonts_address;
/**
* Updates all addresses by inserting gap
*
* @param pos Position to insert bytes
* @param size Number of bytes
*/
public void insertGapAfter(long pos, long size) {
for (Field f : IggyFlashHeader64.class.getDeclaredFields()) {
if (f.getName().endsWith("_address")) {
try {
long val = f.getLong(this);
if (val > pos) {
long newval = val + size;
f.setLong(this, newval);
}
} catch (IllegalAccessException iex) {
//should not happen
}
}
}
}
public boolean isImported() {
return imported == 1;
}
@@ -120,6 +142,10 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
return font_end_address;
}
public void setFontEndAddress(long val) {
this.font_end_address = val;
}
public long getSequenceStartAddress() {
return sequence_start_address;
}
@@ -128,8 +154,8 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
return names_address;
}
public long getUnk8CAddress() {
return unk8C_address;
public long getUnk78Address() {
return unk78_address;
}
public long getUnk80Address() {
@@ -191,8 +217,8 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
off_names = stream.readUI64();
names_address = off_names + stream.position() - 8;
off_unk8C = stream.readUI64();
unk8C_address = off_unk8C + stream.position() - 8;
off_unk78 = stream.readUI64();
unk78_address = off_unk78 + stream.position() - 8;
off_unk80 = stream.readUI64();
unk80_address = off_unk80 + stream.position() - 8;
off_last_section = stream.readUI64();
@@ -211,11 +237,16 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
@Override
public void writeToDataStream(WriteDataStreamInterface stream) throws IOException {
off_start = base_address - stream.position();
stream.writeUI64(off_start);
off_seq_end = sequence_end_address - stream.position();
stream.writeUI64(off_seq_end);
off_font_end = font_end_address - stream.position();
stream.writeUI64(off_font_end);
off_seq_start1 = sequence_start_address - stream.position();
stream.writeUI64(off_seq_start1);
stream.writeUI64(pad_to_match);
off_seq_start2 = sequence_start_address - stream.position();
stream.writeUI64(off_seq_start2);
stream.writeUI32(xmin);
stream.writeUI32(ymin);
@@ -232,12 +263,19 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
stream.writeUI32(additional_import1);
stream.writeUI32(zero1);
stream.writeUI64(unk_guid);
off_names = names_address - stream.position();
stream.writeUI64(off_names);
stream.writeUI64(off_unk8C);
off_unk78 = unk78_address - stream.position();
stream.writeUI64(off_unk78);
off_unk80 = unk80_address - stream.position();
stream.writeUI64(off_unk80);
off_last_section = last_section_address - stream.position();
stream.writeUI64(off_last_section);
off_flash_filename = flash_filename_address - stream.position();
stream.writeUI64(off_flash_filename);
off_decl_strings = decl_strings_address - stream.position();
stream.writeUI64(off_decl_strings);
off_type_of_fonts = type_fonts_address - stream.position();
stream.writeUI64(off_type_of_fonts);
stream.writeUI64(flags);
stream.writeUI32(font_count);

View File

@@ -25,35 +25,57 @@ public class IggySwf implements StructureInterface {
String name;
Map<Integer, IggyFont> fonts;
Map<Integer, IggyText> texts;
Map<Integer, Integer> text2Font;
private IggyFlashHeader64 hdr;
private Map<Long, Long> sizesOfOffsets;
private List<Long> offsets;
private List<IggyTag> tags = new ArrayList<>();
public List<IggyTag> getTags() {
return tags;
}
private byte[] allFontBytes;
public IggySwf(IggyFlashHeader64 header, ReadDataStreamInterface stream, List<Long> offsets) throws IOException {
this.hdr = header;
this.offsets = offsets;
calcSizesFromOffsets();
public IggySwf(ReadDataStreamInterface stream) throws IOException {
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));
private long font_data_addresses[];
private long font_data_sizes[];
private List<Long> text_addresses = new ArrayList<>();
private List<Long> text_data_sizes = new ArrayList<>();
private List<Long> font_add_off = new ArrayList<>();
private List<Long> font_add_size = new ArrayList<>();
public void replaceFontTag(int fontIndex, IggyFont newFont) throws IOException {
long newLen;
byte newData[];
try (WriteDataStreamInterface stream = new TemporaryDataStream()) {
newFont.writeToDataStream(stream);
newData = stream.getAllBytes();
newLen = newData.length;
}
sizesOfOffsets.put(offsets.get(offsets.size() - 1), 0L); //Last offset has 0L length?
long oldLen = font_data_sizes[fontIndex];
long diff = newLen - oldLen;
if (diff != 0) {
font_data_sizes[fontIndex] = newLen;
for (int i = fontIndex; i < hdr.font_count; i++) {
font_data_addresses[i] += diff;
}
for (int i = 0; i < text_addresses.size(); i++) {
text_addresses.set(i, text_addresses.get(i) + diff);
}
for (int i = 0; i < font_add_off.size(); i++) {
font_add_off.set(i, font_add_off.get(i) + diff);
}
}
hdr.insertGapAfter(font_data_addresses[fontIndex], diff);
}
@Override
public void readFromDataStream(ReadDataStreamInterface s) throws IOException {
this.hdr = new IggyFlashHeader64(s);
//Save all font bytes to buffer for later easy modification
long curPos = s.position();
long maxPos = hdr.getFontEndAddress();
allFontBytes = s.readBytes((int) (maxPos - curPos));
s.seek(curPos, SeekMode.SET);
//here is offset[0]
StringBuilder nameBuilder = new StringBuilder();
do {
@@ -71,8 +93,8 @@ public class IggySwf implements StructureInterface {
s.seek(hdr.getBaseAddress(), SeekMode.SET);
s.readUI64(); //one pad
long font_data_addresses[] = new long[(int) hdr.font_count];
long font_data_sizes[] = new long[(int) hdr.font_count];
font_data_addresses = new long[(int) hdr.font_count];
font_data_sizes = new long[(int) hdr.font_count];
for (int i = 0; i < hdr.font_count; i++) {
long offset = s.readUI64();
@@ -85,8 +107,6 @@ public class IggySwf implements StructureInterface {
font_data_sizes[i] = next_offset - offset;
}
}
List<Long> text_addresses = new ArrayList<>();
List<Long> text_data_sizes = new ArrayList<>();
while (true) {
long offset = s.readUI64();
long text_addr = offset + s.position() - 8;
@@ -101,8 +121,6 @@ public class IggySwf implements StructureInterface {
}
}
List<Long> font_add_off = new ArrayList<>();
List<Long> font_add_size = new ArrayList<>();
if (hdr.isImported()) { // tohle muze narusit iggy order, ale oni to pak stejne pocitaji dle infa
long additionalOffset = s.readUI64();
font_add_off.add(additionalOffset + s.position() - 8);
@@ -129,7 +147,6 @@ public class IggySwf implements StructureInterface {
s.seek(font_data_addresses[i], SeekMode.SET);
//byte font_data[] = s.readBytes((int) font_data_sizes[i]);
IggyFont font = new IggyFont(s);
tags.add(font);
fonts.put(i/*??*/, font);
}
@@ -151,30 +168,26 @@ public class IggySwf implements StructureInterface {
}
@Override
public void writeToDataStream(WriteDataStreamInterface stream) throws IOException {
List<Long> newOffsets = new ArrayList<>();
try {
newOffsets.add(stream.position());
for (int i = 0; i < name.length(); i++) {
stream.writeUI16(name.charAt(i));
public void writeToDataStream(WriteDataStreamInterface st) throws IOException {
try (DataStreamInterface s = new TemporaryDataStream(allFontBytes)) {
hdr.writeToDataStream(s);
s.writeUI64(1);
for (int i = 0; i < font_data_addresses.length; i++) {
long offset = font_data_addresses[i] - s.position() + 8;
s.writeUI64(offset);
}
stream.writeUI16(0);
newOffsets.add(stream.position());
long pad8 = 8 - (stream.position() % 8);
for (int i = 0; i < pad8; i++) {
stream.write(0);
s.writeUI64(1);
for (int i = 0; i < text_addresses.size(); i++) {
long offset = text_addresses.get(i) - s.position() + 8;
s.writeUI64(offset);
}
newOffsets.add(stream.position());
for (IggyTag tag : tags) {
tag.writeToDataStream(stream);
newOffsets.add(stream.position());
s.writeUI64(1);
s.seek(840, SeekMode.SET);
for (int i = 0; i < hdr.font_count; i++) {
fonts.get(i).writeToDataStream(s);
}
} catch (IOException ex) {
//ignore
st.writeBytes(s.getAllBytes());
}
this.offsets = newOffsets;
calcSizesFromOffsets();
}
@Override

View File

@@ -35,6 +35,8 @@ public interface WriteDataStreamInterface extends AutoCloseable {
public void seek(long pos, SeekMode mode) throws IOException;
public byte[] getAllBytes() throws IOException;
@Override
public void close();
}