diff --git a/src/com/jpexs/decompiler/flash/abc/ABC.java b/src/com/jpexs/decompiler/flash/abc/ABC.java index 7bc1b2f7f..5385378f7 100644 --- a/src/com/jpexs/decompiler/flash/abc/ABC.java +++ b/src/com/jpexs/decompiler/flash/abc/ABC.java @@ -18,7 +18,6 @@ package com.jpexs.decompiler.flash.abc; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.AVM2Deobfuscation; import com.jpexs.decompiler.flash.abc.avm2.ConstantPool; @@ -56,8 +55,8 @@ import com.jpexs.decompiler.flash.abc.usages.MultinameUsage; import com.jpexs.decompiler.flash.abc.usages.TypeNameMultinameUsage; import com.jpexs.decompiler.flash.helpers.collections.MyEntry; import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import com.jpexs.helpers.MemoryInputStream; import com.jpexs.helpers.utf8.Utf8PrintWriter; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; @@ -336,189 +335,232 @@ public class ABC { } } - public ABC(SWFInputStream is, SWF swf, ABCContainerTag tag) throws IOException { + public ABC(ABCInputStream ais, SWF swf, ABCContainerTag tag) throws IOException { this.swf = swf; this.parentTag = tag; - ABCInputStream ais = new ABCInputStream(is.getBaseStream()); - // put it to the dumpview: - is.readBytesEx(is.available(), "abcBytes"); - minor_version = ais.readU16(); - major_version = ais.readU16(); + minor_version = ais.readU16("minor_version"); + major_version = ais.readU16("major_version"); logger.log(Level.FINE, "ABC minor_version: {0}, major_version: {1}", new Object[]{minor_version, major_version}); + constants = new ConstantPool(); deobfuscation = new AVM2Deobfuscation(constants); + ais.newDumpLevel("constant_pool", "cpool_info"); + //constant integers - int constant_int_pool_count = ais.readU30(); + int constant_int_pool_count = ais.readU30("int_count"); constants.constant_int = new ArrayList<>(constant_int_pool_count); if (constant_int_pool_count > 0) { constants.addInt(0); } - for (int i = 1; i < constant_int_pool_count; i++) { //index 0 not used. Values 1..n-1 - constants.addInt(ais.readS32()); + if (constant_int_pool_count > 1) { + ais.newDumpLevel("integers", "integer[]"); + for (int i = 1; i < constant_int_pool_count; i++) { //index 0 not used. Values 1..n-1 + constants.addInt(ais.readS32("int")); + } + ais.endDumpLevel(); } //constant unsigned integers - int constant_uint_pool_count = ais.readU30(); + int constant_uint_pool_count = ais.readU30("uint_count"); constants.constant_uint = new ArrayList<>(constant_uint_pool_count); if (constant_uint_pool_count > 0) { constants.addUInt(0); } - for (int i = 1; i < constant_uint_pool_count; i++) { //index 0 not used. Values 1..n-1 - constants.addUInt(ais.readU32()); + if (constant_uint_pool_count > 1) { + ais.newDumpLevel("uintegers", "uinteger[]"); + for (int i = 1; i < constant_uint_pool_count; i++) { //index 0 not used. Values 1..n-1 + constants.addUInt(ais.readU32("uint")); + } + ais.endDumpLevel(); } //constant double - int constant_double_pool_count = ais.readU30(); + int constant_double_pool_count = ais.readU30("double_count"); constants.constant_double = new ArrayList<>(constant_double_pool_count); if (constant_double_pool_count > 0) { constants.addDouble(0); } - for (int i = 1; i < constant_double_pool_count; i++) { //index 0 not used. Values 1..n-1 - constants.addDouble(ais.readDouble()); + if (constant_double_pool_count > 1) { + ais.newDumpLevel("doubles", "double[]"); + for (int i = 1; i < constant_double_pool_count; i++) { //index 0 not used. Values 1..n-1 + constants.addDouble(ais.readDouble("double")); + } + ais.endDumpLevel(); } //constant decimal if (minor_version >= MINORwithDECIMAL) { - int constant_decimal_pool_count = ais.readU30(); + int constant_decimal_pool_count = ais.readU30("decimal_count"); constants.constant_decimal = new ArrayList<>(constant_decimal_pool_count); if (constant_decimal_pool_count > 0) { constants.addDecimal(null); } - for (int i = 1; i < constant_decimal_pool_count; i++) { //index 0 not used. Values 1..n-1 - constants.addDecimal(ais.readDecimal()); + if (constant_decimal_pool_count > 1) { + ais.newDumpLevel("decimals", "decimal[]"); + for (int i = 1; i < constant_decimal_pool_count; i++) { //index 0 not used. Values 1..n-1 + constants.addDecimal(ais.readDecimal("decimal")); + } + ais.endDumpLevel(); } } else { constants.constant_decimal = new ArrayList<>(0); } //constant string - int constant_string_pool_count = ais.readU30(); + int constant_string_pool_count = ais.readU30("string_count"); constants.constant_string = new ArrayList<>(constant_string_pool_count); stringOffsets = new long[constant_string_pool_count]; if (constant_string_pool_count > 0) { constants.addString(""); } - for (int i = 1; i < constant_string_pool_count; i++) { //index 0 not used. Values 1..n-1 - long pos = ais.getPosition(); - constants.addString(ais.readString()); - stringOffsets[i] = pos; + if (constant_string_pool_count > 1) { + ais.newDumpLevel("strings", "string[]"); + for (int i = 1; i < constant_string_pool_count; i++) { //index 0 not used. Values 1..n-1 + long pos = ais.getPosition(); + constants.addString(ais.readString("string")); + stringOffsets[i] = pos; + } + ais.endDumpLevel(); } //constant namespace - int constant_namespace_pool_count = ais.readU30(); + int constant_namespace_pool_count = ais.readU30("namespace_count"); constants.constant_namespace = new ArrayList<>(constant_namespace_pool_count); if (constant_namespace_pool_count > 0) { constants.addNamespace(null); } - for (int i = 1; i < constant_namespace_pool_count; i++) { //index 0 not used. Values 1..n-1 - constants.addNamespace(ais.readNamespace()); + if (constant_namespace_pool_count > 1) { + ais.newDumpLevel("namespaces", "namespace[]"); + for (int i = 1; i < constant_namespace_pool_count; i++) { //index 0 not used. Values 1..n-1 + constants.addNamespace(ais.readNamespace("namespace")); + } + ais.endDumpLevel(); } //constant namespace set - int constant_namespace_set_pool_count = ais.readU30(); + int constant_namespace_set_pool_count = ais.readU30("ns_set_count"); constants.constant_namespace_set = new ArrayList<>(constant_namespace_set_pool_count); if (constant_namespace_set_pool_count > 0) { constants.addNamespaceSet(null); } - for (int i = 1; i < constant_namespace_set_pool_count; i++) { //index 0 not used. Values 1..n-1 - constants.addNamespaceSet(new NamespaceSet()); - int namespace_count = ais.readU30(); - constants.getNamespaceSet(i).namespaces = new int[namespace_count]; - for (int j = 0; j < namespace_count; j++) { - constants.getNamespaceSet(i).namespaces[j] = ais.readU30(); + if (constant_namespace_set_pool_count > 1) { + ais.newDumpLevel("ns_sets", "ns_set[]"); + for (int i = 1; i < constant_namespace_set_pool_count; i++) { //index 0 not used. Values 1..n-1 + ais.newDumpLevel("ns_set_infos", "ns_set_info[]"); + constants.addNamespaceSet(new NamespaceSet()); + int namespace_count = ais.readU30("count"); + constants.getNamespaceSet(i).namespaces = new int[namespace_count]; + for (int j = 0; j < namespace_count; j++) { + constants.getNamespaceSet(i).namespaces[j] = ais.readU30("ns"); + } + ais.endDumpLevel(); } + ais.endDumpLevel(); } //constant multiname - int constant_multiname_pool_count = ais.readU30(); + int constant_multiname_pool_count = ais.readU30("multiname_count"); constants.constant_multiname = new ArrayList<>(constant_multiname_pool_count); if (constant_multiname_pool_count > 0) { constants.addMultiname(null); } - for (int i = 1; i < constant_multiname_pool_count; i++) { //index 0 not used. Values 1..n-1 - constants.addMultiname(ais.readMultiname()); + if (constant_multiname_pool_count > 1) { + ais.newDumpLevel("multiname", "multinames[]"); + for (int i = 1; i < constant_multiname_pool_count; i++) { //index 0 not used. Values 1..n-1 + constants.addMultiname(ais.readMultiname("multiname")); + } + ais.endDumpLevel(); } + + ais.endDumpLevel(); //cpool_info //method info - int methods_count = ais.readU30(); - method_info = new ArrayList<>();//MethodInfo[methods_count]; - bodyIdxFromMethodIdx = new ArrayList<>(); //[methods_count]; + int methods_count = ais.readU30("methods_count"); + method_info = new ArrayList<>(methods_count); //MethodInfo[methods_count]; + bodyIdxFromMethodIdx = new ArrayList<>(methods_count); //[methods_count]; for (int i = 0; i < methods_count; i++) { - method_info.add(ais.readMethodInfo()); + method_info.add(ais.readMethodInfo("method")); bodyIdxFromMethodIdx.add(-1); } //metadata info - int metadata_count = ais.readU30(); - metadata_info = new ArrayList<>(); + int metadata_count = ais.readU30("metadata_count"); + metadata_info = new ArrayList<>(metadata_count); for (int i = 0; i < metadata_count; i++) { - int name_index = ais.readU30(); - int values_count = ais.readU30(); + int name_index = ais.readU30("name_index"); + int values_count = ais.readU30("values_count"); int[] keys = new int[values_count]; for (int v = 0; v < values_count; v++) { - keys[v] = ais.readU30(); + keys[v] = ais.readU30("key"); } int[] values = new int[values_count]; for (int v = 0; v < values_count; v++) { - values[v] = ais.readU30(); + values[v] = ais.readU30("value"); } metadata_info.add(new MetadataInfo(name_index, keys, values)); } - int class_count = ais.readU30(); - instance_info = new ArrayList<>(); //InstanceInfo[class_count]; + int class_count = ais.readU30("class_count"); + instance_info = new ArrayList<>(class_count); //InstanceInfo[class_count]; for (int i = 0; i < class_count; i++) { - instance_info.add(ais.readInstanceInfo()); + instance_info.add(ais.readInstanceInfo("instance")); } - class_info = new ArrayList<>(); //ClassInfo[class_count]; + class_info = new ArrayList<>(class_count); //ClassInfo[class_count]; for (int i = 0; i < class_count; i++) { + ais.newDumpLevel("class", "class_info"); ClassInfo ci = new ClassInfo(); - ci.cinit_index = ais.readU30(); - ci.static_traits = ais.readTraits(); + ci.cinit_index = ais.readU30("cinit_index"); + ci.static_traits = ais.readTraits("static_traits"); class_info.add(ci); + ais.endDumpLevel(); } - int script_count = ais.readU30(); - script_info = new ArrayList<>(); //ScriptInfo[script_count]; + int script_count = ais.readU30("script_count"); + script_info = new ArrayList<>(script_count); //ScriptInfo[script_count]; for (int i = 0; i < script_count; i++) { + ais.newDumpLevel("script", "script_info"); ScriptInfo si = new ScriptInfo(); - si.init_index = ais.readU30(); - si.traits = ais.readTraits(); + si.init_index = ais.readU30("init_index"); + si.traits = ais.readTraits("traits"); script_info.add(si); + ais.endDumpLevel(); } - int bodies_count = ais.readU30(); - bodies = new ArrayList<>(); //MethodBody[bodies_count]; + int bodies_count = ais.readU30("bodies_count"); + bodies = new ArrayList<>(bodies_count); //MethodBody[bodies_count]; for (int i = 0; i < bodies_count; i++) { + ais.newDumpLevel("method_body", "method_body_info"); MethodBody mb = new MethodBody(); - mb.method_info = ais.readU30(); - mb.max_stack = ais.readU30(); - mb.max_regs = ais.readU30(); - mb.init_scope_depth = ais.readU30(); - mb.max_scope_depth = ais.readU30(); - int code_length = ais.readU30(); - mb.codeBytes = ais.readBytes(code_length); + mb.method_info = ais.readU30("method_info"); + mb.max_stack = ais.readU30("max_stack"); + mb.max_regs = ais.readU30("max_regs"); + mb.init_scope_depth = ais.readU30("init_scope_depth"); + mb.max_scope_depth = ais.readU30("max_scope_depth"); + int code_length = ais.readU30("code_length"); + mb.codeBytes = ais.readBytes(code_length, "code"); try { - mb.code = new AVM2Code(new ByteArrayInputStream(mb.codeBytes)); + ABCInputStream ais2 = new ABCInputStream(new MemoryInputStream(mb.codeBytes)); + mb.code = new AVM2Code(ais2); } catch (UnknownInstructionCode re) { mb.code = new AVM2Code(); Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, null, re); } mb.code.compact(); - int ex_count = ais.readU30(); + int ex_count = ais.readU30("ex_count"); mb.exceptions = new ABCException[ex_count]; for (int j = 0; j < ex_count; j++) { ABCException abce = new ABCException(); - abce.start = ais.readU30(); - abce.end = ais.readU30(); - abce.target = ais.readU30(); - abce.type_index = ais.readU30(); - abce.name_index = ais.readU30(); + abce.start = ais.readU30("start"); + abce.end = ais.readU30("end"); + abce.target = ais.readU30("target"); + abce.type_index = ais.readU30("type_index"); + abce.name_index = ais.readU30("name_index"); mb.exceptions[j] = abce; } - mb.traits = ais.readTraits(); + mb.traits = ais.readTraits("traits"); bodies.add(mb); method_info.get(mb.method_info).setBody(mb); bodyIdxFromMethodIdx.set(mb.method_info, i); + ais.endDumpLevel(); } loadNamespaceMap(); /*for(int i=0;i> 7) == 1; i &= 0x7f; ret += (((long) i) << bytePos); @@ -128,32 +170,52 @@ public class ABCInputStream extends InputStream { return ret; } - public int readU30() throws IOException { - return (int) readU32(); + public long readU32(String name) throws IOException { + newDumpLevel(name, "U32"); + long ret = readU32Internal(); + endDumpLevel(ret); + return ret; } - public int readS24() throws IOException { - int ret = (read()) + (read() << 8) + (read() << 16); + private int readU30Internal() throws IOException { + return (int) readU32Internal(); + } + + public int readU30(String name) throws IOException { + newDumpLevel(name, "U30"); + int ret = readU30Internal(); + endDumpLevel(ret); + return ret; + } + + public int readS24(String name) throws IOException { + newDumpLevel(name, "S24"); + int ret = (readInternal()) + (readInternal() << 8) + (readInternal() << 16); if ((ret >> 23) == 1) { ret |= 0xff000000; } + endDumpLevel(ret); return ret; } - public int readU16() throws IOException { - return (read()) + (read() << 8); + public int readU16(String name) throws IOException { + newDumpLevel(name, "U16"); + int ret = (readInternal()) + (readInternal() << 8); + endDumpLevel(ret); + return ret; } - public long readS32() throws IOException { + public long readS32(String name) throws IOException { int i; long ret = 0; int bytePos = 0; int byteCount = 0; boolean nextByte; + newDumpLevel(name, "S32"); do { - i = read(); + i = readInternal(); nextByte = (i >> 7) == 1; i &= 0x7f; ret += (i << bytePos); @@ -166,15 +228,15 @@ public class ABCInputStream extends InputStream { break; } } while (nextByte); + endDumpLevel(ret); return ret; } - @Override public int available() throws IOException { return is.available(); } - public final long readLong() throws IOException { + private final long readLong() throws IOException { byte[] readBuffer = safeRead(8); return (((long) readBuffer[7] << 56) + ((long) (readBuffer[6] & 255) << 48) @@ -186,99 +248,109 @@ public class ABCInputStream extends InputStream { + ((readBuffer[0] & 255))); } - public double readDouble() throws IOException { + public double readDouble(String name) throws IOException { + newDumpLevel(name, "Double"); long el = readLong(); double ret = Double.longBitsToDouble(el); + endDumpLevel(ret); return ret; } private byte[] safeRead(int count) throws IOException { byte[] ret = new byte[count]; for (int i = 0; i < count; i++) { - ret[i] = (byte) read(); + ret[i] = (byte) readInternal(); } return ret; } - public Namespace readNamespace() throws IOException { - int kind = read(); + public Namespace readNamespace(String name) throws IOException { + newDumpLevel(name, "Namespace"); + int kind = read("kind"); int name_index = 0; for (int k = 0; k < Namespace.nameSpaceKinds.length; k++) { if (Namespace.nameSpaceKinds[k] == kind) { - name_index = readU30(); + name_index = readU30("name_index"); break; } } + endDumpLevel(); return new Namespace(kind, name_index); } - public Multiname readMultiname() throws IOException { - int kind = readU8(); + public Multiname readMultiname(String name) throws IOException { + int kind = readU8("kind"); int namespace_index = 0; int name_index = 0; int namespace_set_index = 0; int qname_index = 0; List params = new ArrayList<>(); + newDumpLevel(name, "Multiname"); if ((kind == Multiname.QNAME) || (kind == Multiname.QNAMEA)) { - namespace_index = readU30(); - name_index = readU30(); + namespace_index = readU30("namespace_index"); + name_index = readU30("name_index"); } else if ((kind == Multiname.RTQNAME) || (kind == Multiname.RTQNAMEA)) { - name_index = readU30(); + name_index = readU30("name_index"); } else if ((kind == Multiname.RTQNAMEL) || (kind == Multiname.RTQNAMELA)) { } else if ((kind == Multiname.MULTINAME) || (kind == Multiname.MULTINAMEA)) { - name_index = readU30(); - namespace_set_index = readU30(); + name_index = readU30("name_index"); + namespace_set_index = readU30("namespace_set_index"); } else if ((kind == Multiname.MULTINAMEL) || (kind == Multiname.MULTINAMELA)) { - namespace_set_index = readU30(); + namespace_set_index = readU30("namespace_set_index"); } else if (kind == Multiname.TYPENAME) { - qname_index = readU30(); //Multiname index!!! - int paramsLength = readU30(); + qname_index = readU30("qname_index"); //Multiname index!!! + int paramsLength = readU30("paramsLength"); for (int i = 0; i < paramsLength; i++) { - params.add(readU30()); //multiname indices! + params.add(readU30("param")); //multiname indices! } } else { throw new IOException("Unknown kind of Multiname:0x" + Integer.toHexString(kind)); } + endDumpLevel(); return new Multiname(kind, name_index, namespace_index, namespace_set_index, qname_index, params); } - public MethodInfo readMethodInfo() throws IOException { - int param_count = readU30(); - int ret_type = readU30(); + public MethodInfo readMethodInfo(String name) throws IOException { + newDumpLevel(name, "method_info"); + int param_count = readU30("param_count"); + int ret_type = readU30("ret_type"); int[] param_types = new int[param_count]; for (int i = 0; i < param_count; i++) { - param_types[i] = readU30(); + param_types[i] = readU30("param_type"); } - int name_index = readU30(); - int flags = read(); + int name_index = readU30("name_index"); + int flags = readInternal(); //// 1=need_arguments, 2=need_activation, 4=need_rest 8=has_optional (16=ignore_rest, 32=explicit,) 64=setsdxns, 128=has_paramnames ValueKind[] optional = new ValueKind[0]; if ((flags & 8) == 8) { //if has_optional - int optional_count = readU30(); + int optional_count = readU30("optional_count"); optional = new ValueKind[optional_count]; for (int i = 0; i < optional_count; i++) { - optional[i] = new ValueKind(readU30(), read()); + optional[i] = new ValueKind(readU30("value_index"), read("value_kind")); } } int[] param_names = new int[param_count]; if ((flags & 128) == 128) { //if has_paramnames for (int i = 0; i < param_count; i++) { - param_names[i] = readU30(); + param_names[i] = readU30("param_name"); } } + + endDumpLevel(); return new MethodInfo(param_types, ret_type, name_index, flags, optional, param_names); } - public Trait readTrait() throws IOException { + public Trait readTrait(String name) throws IOException { + newDumpLevel(name, "Trait"); long pos = getPosition(); startBuffer(); - int name_index = readU30(); - int kind = read(); + int name_index = readU30("name_index"); + int kind = readInternal(); int kindType = 0xf & kind; int kindFlags = kind >> 4; Trait trait; @@ -287,11 +359,11 @@ public class ABCInputStream extends InputStream { case 0: //slot case 6: //const TraitSlotConst t1 = new TraitSlotConst(); - t1.slot_id = readU30(); - t1.type_index = readU30(); - t1.value_index = readU30(); + t1.slot_id = readU30("slot_id"); + t1.type_index = readU30("type_index"); + t1.value_index = readU30("value_index"); if (t1.value_index != 0) { - t1.value_kind = read(); + t1.value_kind = readInternal(); } trait = t1; break; @@ -299,20 +371,20 @@ public class ABCInputStream extends InputStream { case 2: //getter case 3: //setter TraitMethodGetterSetter t2 = new TraitMethodGetterSetter(); - t2.disp_id = readU30(); - t2.method_info = readU30(); + t2.disp_id = readU30("disp_id"); + t2.method_info = readU30("method_info"); trait = t2; break; case 4: //class TraitClass t3 = new TraitClass(); - t3.slot_id = readU30(); - t3.class_info = readU30(); + t3.slot_id = readU30("slot_id"); + t3.class_info = readU30("class_info"); trait = t3; break; case 5: //function TraitFunction t4 = new TraitFunction(); - t4.slot_id = readU30(); - t4.method_info = readU30(); + t4.slot_id = readU30("slot_id"); + t4.method_info = readU30("method_info"); trait = t4; break; default: @@ -323,61 +395,77 @@ public class ABCInputStream extends InputStream { trait.kindFlags = kindFlags; trait.name_index = name_index; if ((kindFlags & ATTR_METADATA) != 0) { - int metadata_count = readU30(); + int metadata_count = readU30("metadata_count"); trait.metadata = new int[metadata_count]; for (int i = 0; i < metadata_count; i++) { - trait.metadata[i] = readU30(); + trait.metadata[i] = readU30("metadata"); } } trait.bytes = stopBuffer(); + endDumpLevel(); return trait; } - public Traits readTraits() throws IOException { - int count = readU30(); + public Traits readTraits(String name) throws IOException { + newDumpLevel(name, "Traits"); + int count = readU30("count"); Traits traits = new Traits(); traits.traits = new ArrayList<>(); for (int i = 0; i < count; i++) { - traits.traits.add(readTrait()); + traits.traits.add(readTrait("trait")); } + endDumpLevel(); return traits; } - public byte[] readBytes(int count) throws IOException { + public byte[] readBytesInternal(int count) throws IOException { byte[] ret = new byte[count]; for (int i = 0; i < count; i++) { - ret[i] = (byte) read(); + ret[i] = (byte) readInternal(); } return ret; } - public Decimal readDecimal() throws IOException { - byte[] data = readBytes(16); + public byte[] readBytes(int count, String name) throws IOException { + newDumpLevel(name, "Bytes"); + byte[] ret = readBytesInternal(count); + endDumpLevel(); + return ret; + } + + public Decimal readDecimal(String name) throws IOException { + newDumpLevel(name, "Decimal"); + byte[] data = readBytesInternal(16); + endDumpLevel(); return new Decimal(data); } - public InstanceInfo readInstanceInfo() throws IOException { + public InstanceInfo readInstanceInfo(String name) throws IOException { + newDumpLevel(name, "instance_info"); InstanceInfo ret = new InstanceInfo(); - ret.name_index = readU30(); - ret.super_index = readU30(); - ret.flags = read(); + ret.name_index = readU30("name_index"); + ret.super_index = readU30("super_index"); + ret.flags = readInternal(); if ((ret.flags & CLASS_PROTECTED_NS) != 0) { - ret.protectedNS = readU30(); + ret.protectedNS = readU30("protectedNS"); } - int interfaces_count = readU30(); + int interfaces_count = readU30("interfaces_count"); ret.interfaces = new int[interfaces_count]; for (int i = 0; i < interfaces_count; i++) { - ret.interfaces[i] = readU30(); + ret.interfaces[i] = readU30("interface"); } - ret.iinit_index = readU30(); - ret.instance_traits = readTraits(); + ret.iinit_index = readU30("iinit_index"); + ret.instance_traits = readTraits("instance_traits"); + endDumpLevel(); return ret; } - public String readString() throws IOException { - int length = readU30(); + public String readString(String name) throws IOException { + newDumpLevel(name, "String"); + int length = readU30Internal(); byte[] b = safeRead(length); String r = new String(b, Utf8Helper.charset); + endDumpLevel(r); return r; } diff --git a/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 97698b00e..c909199d6 100644 --- a/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -214,6 +214,7 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; import com.jpexs.decompiler.flash.abc.types.traits.Traits; import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.dumpview.DumpInfo; import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -231,7 +232,6 @@ import com.jpexs.helpers.Helper; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; @@ -784,46 +784,51 @@ public class AVM2Code implements Serializable { return null; } - public AVM2Code(InputStream is) throws IOException { - ABCInputStream ais = new ABCInputStream(is); + public AVM2Code(ABCInputStream ais) throws IOException { while (ais.available() > 0) { + DumpInfo di = ais.newDumpLevel("instruction", "instruction"); long startOffset = ais.getPosition(); ais.startBuffer(); - int instructionCode = ais.read(); + int instructionCode = ais.read("instructionCode"); InstructionDefinition instr = instructionSetByCode[instructionCode]; + if (di != null) { + di.name = instr.instructionName; + } if (instr != null) { int[] actualOperands; if (instructionCode == 0x1b) { //switch - int firstOperand = ais.readS24(); - int case_count = ais.readU30(); + int firstOperand = ais.readS24("firstOperand"); + int case_count = ais.readU30("case_count"); actualOperands = new int[case_count + 3]; actualOperands[0] = firstOperand; actualOperands[1] = case_count; for (int c = 0; c < case_count + 1; c++) { - actualOperands[2 + c] = ais.readS24(); + actualOperands[2 + c] = ais.readS24("actualOperand"); } } else { actualOperands = new int[instr.operands.length]; for (int op = 0; op < instr.operands.length; op++) { switch (instr.operands[op] & 0xff00) { case OPT_U30: - actualOperands[op] = ais.readU30(); + actualOperands[op] = ais.readU30("operand"); break; case OPT_U8: - actualOperands[op] = ais.read(); + actualOperands[op] = ais.read("operand"); break; case OPT_BYTE: - actualOperands[op] = (byte) ais.read(); + actualOperands[op] = (byte) ais.read("operand"); break; case OPT_S24: - actualOperands[op] = ais.readS24(); + actualOperands[op] = ais.readS24("operand"); break; } } } code.add(new AVM2Instruction(startOffset, instr, actualOperands, ais.stopBuffer())); + ais.endDumpLevel(instr.instructionCode); } else { + ais.endDumpLevel(instr.instructionCode); break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions) //throw new UnknownInstructionCode(instructionCode); } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java index a38fa9060..abd723b5a 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.gui.abc; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ABCInputStream; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.ConstantPool; import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode; @@ -36,7 +37,7 @@ import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.helpers.Helper; -import java.io.ByteArrayInputStream; +import com.jpexs.helpers.MemoryInputStream; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; @@ -194,7 +195,8 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretLi MethodBody mb = abc.bodies.get(bodyIndex); mb.codeBytes = data; try { - mb.code = new AVM2Code(new ByteArrayInputStream(mb.codeBytes)); + ABCInputStream ais = new ABCInputStream(new MemoryInputStream(mb.codeBytes)); + mb.code = new AVM2Code(ais); } catch (UnknownInstructionCode re) { mb.code = new AVM2Code(); Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, null, re); diff --git a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java index ed0daaaf6..eb5548f16 100644 --- a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java +++ b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java @@ -18,6 +18,9 @@ package com.jpexs.decompiler.flash.gui.dumpview; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ABCInputStream; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionListReader; import com.jpexs.decompiler.flash.action.model.ConstantPool; @@ -28,6 +31,7 @@ import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.decompiler.flash.gui.MainPanel; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.helpers.Helper; +import com.jpexs.helpers.MemoryInputStream; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; @@ -64,6 +68,8 @@ public class DumpTree extends JTree implements ActionListener { private static final String ACTION_EXPAND_RECURSIVE = "EXPANDRECURSIVE"; private static final String ACTION_SAVE_TO_FILE = "SAVETOFILE"; private static final String ACTION_PARSE_ACTIONS = "PARSEACTIONS"; + private static final String ACTION_PARSE_ABC = "PARSEABC"; + private static final String ACTION_PARSE_INSTRUCTIONS = "PARSEINSTRUCTIONS"; private final MainPanel mainPanel; @@ -131,6 +137,16 @@ public class DumpTree extends JTree implements ActionListener { parseActionsMenuItem.addActionListener(this); contextPopupMenu.add(parseActionsMenuItem); + final JMenuItem parseAbcMenuItem = new JMenuItem(mainPanel.translate("contextmenu.parseABC")); + parseAbcMenuItem.setActionCommand(ACTION_PARSE_ABC); + parseAbcMenuItem.addActionListener(this); + contextPopupMenu.add(parseAbcMenuItem); + + final JMenuItem parseInstructionsMenuItem = new JMenuItem(mainPanel.translate("contextmenu.parseInstructions")); + parseInstructionsMenuItem.setActionCommand(ACTION_PARSE_INSTRUCTIONS); + parseInstructionsMenuItem.addActionListener(this); + contextPopupMenu.add(parseInstructionsMenuItem); + addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -150,6 +166,8 @@ public class DumpTree extends JTree implements ActionListener { expandRecursiveMenuItem.setVisible(false); saveToFileMenuItem.setVisible(false); parseActionsMenuItem.setVisible(false); + parseAbcMenuItem.setVisible(false); + parseInstructionsMenuItem.setVisible(false); if (paths.length == 1) { DumpInfo treeNode = (DumpInfo) paths[0].getLastPathComponent(); @@ -162,10 +180,19 @@ public class DumpTree extends JTree implements ActionListener { saveToFileMenuItem.setVisible(true); } + // todo honfika: do not use string names, because it has conflicts e.g with DefineFont.code if (treeNode.name.equals("actionBytes") && treeNode.getChildCount() == 0) { parseActionsMenuItem.setVisible(true); } + if (treeNode.name.equals("abcBytes") && treeNode.getChildCount() == 0) { + parseAbcMenuItem.setVisible(true); + } + + if (treeNode.name.equals("code") && treeNode.parent.name.equals("method_body") && treeNode.getChildCount() == 0) { + parseInstructionsMenuItem.setVisible(true); + } + TreeModel model = getModel(); expandRecursiveMenuItem.setVisible(model.getChildCount(treeNode) > 0); } @@ -229,11 +256,46 @@ public class DumpTree extends JTree implements ActionListener { rri.readAction(new ConstantPool()); dumpInfo.getChildInfos().add(di); } + repaint(); } catch (IOException | InterruptedException ex) { Logger.getLogger(DumpTree.class.getName()).log(Level.SEVERE, null, ex); } } break; + case ACTION_PARSE_ABC: { + TreePath[] paths = getSelectionPaths(); + DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent(); + SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf(); + byte[] data = swf.uncompressedData; + int prevLength = (int) dumpInfo.startByte; + try { + ABCInputStream ais = new ABCInputStream(new MemoryInputStream(data, 0, prevLength + (int) dumpInfo.lengthBytes)); + ais.seek(prevLength); + ais.dumpInfo = dumpInfo; + new ABC(ais, swf, null); + } catch (IOException ex) { + Logger.getLogger(DumpTree.class.getName()).log(Level.SEVERE, null, ex); + } + repaint(); + } + break; + case ACTION_PARSE_INSTRUCTIONS: { + TreePath[] paths = getSelectionPaths(); + DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent(); + SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf(); + byte[] data = swf.uncompressedData; + int prevLength = (int) dumpInfo.startByte; + try { + ABCInputStream ais = new ABCInputStream(new MemoryInputStream(data, 0, prevLength + (int) dumpInfo.lengthBytes)); + ais.seek(prevLength); + ais.dumpInfo = dumpInfo; + new AVM2Code(ais); + } catch (IOException ex) { + Logger.getLogger(DumpTree.class.getName()).log(Level.SEVERE, null, ex); + } + repaint(); + } + break; case ACTION_CLOSE_SWF: { Main.closeFile(mainPanel.getCurrentSwfList()); } diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 5e5341706..cf90005b1 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -511,3 +511,5 @@ header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixels contextmenu.saveToFile = Save to File contextmenu.parseActions = Parse actions +contextmenu.parseABC = Parse ABC +contextmenu.parseInstructions = Parse AVM2 Instrctions diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties index 5124c5040..a0f74fc10 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties @@ -511,3 +511,5 @@ header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% k\u00e9ppont contextmenu.saveToFile = Ment\u00e9s f\u00e1jlba contextmenu.parseActions = Action-\u00f6k elemz\u00e9se +contextmenu.parseABC = ABC elemz\u00e9se +contextmenu.parseInstructions = AVM2 utas\u00edt\u00e1sok elemz\u00e9se diff --git a/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java b/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java index c43a9fe31..1c139ce5f 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ABCInputStream; import com.jpexs.decompiler.flash.abc.CopyOutputStream; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.types.BasicType; @@ -74,7 +75,11 @@ public class DoABCDefineTag extends Tag implements ABCContainerTag { super(sis.getSwf(), ID, "DoABCDefine", data); flags = sis.readUI32("flags"); name = sis.readString("name"); - abc = new ABC(sis, swf, this); + + ABCInputStream ais = new ABCInputStream(sis.getBaseStream()); + // put it to the dumpview: + sis.readBytesEx(sis.available(), "abcBytes"); + abc = new ABC(ais, swf, this); } /** diff --git a/src/com/jpexs/decompiler/flash/tags/DoABCTag.java b/src/com/jpexs/decompiler/flash/tags/DoABCTag.java index 12f9305ad..9c7392c75 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoABCTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoABCTag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ABCInputStream; import com.jpexs.decompiler.flash.abc.CopyOutputStream; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.types.annotations.Internal; @@ -59,7 +60,11 @@ public class DoABCTag extends Tag implements ABCContainerTag { */ public DoABCTag(SWFInputStream sis, ByteArrayRange data) throws IOException { super(sis.getSwf(), ID, "DoABC", data); - abc = new ABC(sis, swf, this); + + ABCInputStream ais = new ABCInputStream(sis.getBaseStream()); + // put it to the dumpview: + sis.readBytesEx(sis.available(), "abcBytes"); + abc = new ABC(ais, swf, this); } /**