From 2df49d32a71818227e80a8628688906f2ede8a6a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 2 Sep 2014 20:56:03 +0400 Subject: [PATCH] java-decompiler: fixes and cleanups - unified attribute loading code - common methods for checking member flags - verifying skip() - correct resource closing - typos --- .../java/decompiler/main/AssertProcessor.java | 11 +- .../main/ClassReference14Processor.java | 62 ++-- .../java/decompiler/main/ClassWriter.java | 62 ++-- .../decompiler/main/ClassesProcessor.java | 9 +- .../java/decompiler/main/EnumProcessor.java | 5 +- .../decompiler/main/InitializerProcessor.java | 2 +- .../decompiler/main/rels/ClassWrapper.java | 2 +- .../main/rels/NestedClassProcessor.java | 10 +- .../main/rels/NestedMemberAccess.java | 53 ++- .../modules/decompiler/IdeaNotNullHelper.java | 2 +- .../decompiler/exps/AssignmentExprent.java | 47 ++- .../decompiler/exps/InvocationExprent.java | 13 +- .../sforms/SSAConstructorSparseEx.java | 3 +- .../sforms/SSAUConstructorSparseEx.java | 3 +- .../decompiler/vars/VarDefinitionHelper.java | 2 +- .../decompiler/vars/VarTypeProcessor.java | 2 +- .../decompiler/vars/VarVersionsProcessor.java | 2 +- .../modules/renamer/IdentifierConverter.java | 8 +- .../java/decompiler/struct/ContextUnit.java | 11 +- .../java/decompiler/struct/StructClass.java | 298 ++++------------ .../java/decompiler/struct/StructContext.java | 15 +- .../java/decompiler/struct/StructField.java | 92 ++--- .../java/decompiler/struct/StructMember.java | 87 +++++ .../java/decompiler/struct/StructMethod.java | 317 ++++-------------- .../attr/StructExceptionsAttribute.java | 27 -- .../struct/attr/StructGeneralAttribute.java | 95 ++---- .../struct/consts/ConstantPool.java | 148 ++++---- .../java/decompiler/struct/gen/DataPoint.java | 2 +- .../decompiler/struct/lazy/LazyLoader.java | 155 ++++----- .../decompiler/util/DataInputFullStream.java | 17 +- .../java/decompiler/SingleClassesTest.java | 2 + 31 files changed, 569 insertions(+), 995 deletions(-) create mode 100644 src/org/jetbrains/java/decompiler/struct/StructMember.java diff --git a/src/org/jetbrains/java/decompiler/main/AssertProcessor.java b/src/org/jetbrains/java/decompiler/main/AssertProcessor.java index fcef8d7..da703fd 100644 --- a/src/org/jetbrains/java/decompiler/main/AssertProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/AssertProcessor.java @@ -69,7 +69,7 @@ public class AssertProcessor { ClassWrapper wrapper = node.wrapper; - boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); + boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); for (StructField fd : wrapper.getClassStruct().getFields()) { @@ -78,12 +78,8 @@ public class AssertProcessor { // initializer exists if (wrapper.getStaticFieldInitializers().containsKey(keyField)) { - int flags = fd.access_flags; - boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic"); - // access flags set - if ((flags & CodeConstants.ACC_STATIC) != 0 && (flags & CodeConstants.ACC_FINAL) != 0 && - (isSynthetic || nosynthflag)) { + if (fd.hasModifier(CodeConstants.ACC_STATIC) && fd.hasModifier(CodeConstants.ACC_FINAL) && (noSynthFlag || fd.isSynthetic())) { // field type boolean FieldDescriptor fdescr = FieldDescriptor.parseDescriptor(fd.getDescriptor()); @@ -100,8 +96,7 @@ public class AssertProcessor { if (invexpr.getInstance() != null && invexpr.getInstance().type == Exprent.EXPRENT_CONST && - "desiredAssertionStatus".equals(invexpr.getName()) - && + "desiredAssertionStatus".equals(invexpr.getName()) && "java/lang/Class".equals(invexpr.getClassname()) && invexpr.getLstParameters().isEmpty()) { diff --git a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java index c912bf7..4552b1d 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java @@ -33,10 +33,7 @@ import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.VBStyleCollection; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; +import java.util.*; import java.util.Map.Entry; public class ClassReference14Processor { @@ -105,7 +102,7 @@ public class ClassReference14Processor { // find the synthetic method Class class$(String) if present HashMap mapClassMeths = new HashMap(); - findClassMethod(node, mapClassMeths); + mapClassMethods(node, mapClassMeths); if (mapClassMeths.isEmpty()) { return; @@ -176,37 +173,33 @@ public class ClassReference14Processor { } } - private void findClassMethod(ClassNode node, HashMap mapClassMeths) { - - boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); + private void mapClassMethods(ClassNode node, Map map) { + boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); ClassWrapper wrapper = node.wrapper; - for (MethodWrapper meth : wrapper.getMethods()) { - StructMethod mt = meth.methodStruct; + for (MethodWrapper method : wrapper.getMethods()) { + StructMethod mt = method.methodStruct; - if (((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic") - || nosynthflag) && + if ((noSynthFlag || mt.isSynthetic()) && mt.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") && - (mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0) { - - RootStatement root = meth.root; - if (root != null) { - if (root.getFirst().type == Statement.TYPE_TRYCATCH) { - CatchStatement cst = (CatchStatement)root.getFirst(); - if (cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK && - cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK && - cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"))) { - - BasicBlockStatement body = (BasicBlockStatement)cst.getFirst(); - BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1); - - if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) { - if (bodyexprent.equals(body.getExprents().get(0)) && - handlerexprent.equals(handler.getExprents().get(0))) { - mapClassMeths.put(wrapper, meth); - break; - } + mt.hasModifier(CodeConstants.ACC_STATIC)) { + + RootStatement root = method.root; + if (root != null && root.getFirst().type == Statement.TYPE_TRYCATCH) { + CatchStatement cst = (CatchStatement)root.getFirst(); + if (cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK && + cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK && + cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"))) { + + BasicBlockStatement body = (BasicBlockStatement)cst.getFirst(); + BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1); + + if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) { + if (bodyexprent.equals(body.getExprents().get(0)) && + handlerexprent.equals(handler.getExprents().get(0))) { + map.put(wrapper, method); + break; } } } @@ -216,7 +209,7 @@ public class ClassReference14Processor { // iterate nested classes for (ClassNode nd : node.nested) { - findClassMethod(nd, mapClassMeths); + mapClassMethods(nd, map); } } @@ -269,9 +262,8 @@ public class ClassReference14Processor { StructField fd = wrapper.getClassStruct().getField(field.getName(), field.getDescriptor().descriptorString); // FIXME: can be null! why?? - if (fd != null && (fd.access_flags & CodeConstants.ACC_STATIC) != 0 && - ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic") - || DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) { + if (fd != null && fd.hasModifier(CodeConstants.ACC_STATIC) && + (fd.isSynthetic() || DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) { if (fexpr.getLstOperands().get(1).type == Exprent.EXPRENT_ASSIGNMENT && fexpr.getLstOperands().get(2).equals(field)) { AssignmentExprent asexpr = (AssignmentExprent)fexpr.getLstOperands().get(1); diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 5258dee..c6dc7a4 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -99,7 +99,7 @@ public class ClassWriter { ref14processor.processClassReferences(node); } - if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (cl.access_flags & CodeConstants.ACC_ENUM) != 0) { + if (cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM)) { EnumProcessor.clearEnum(wrapper); } @@ -234,11 +234,8 @@ public class ClassWriter { boolean mthidden = false; for (StructMethod mt : cl.getMethods()) { - - int flags = mt.getAccessFlags(); - - boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic"); - boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0; + boolean isSynthetic = mt.isSynthetic(); + boolean isBridge = mt.hasModifier(CodeConstants.ACC_BRIDGE); if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) && (!isBridge || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE)) && @@ -262,12 +259,10 @@ public class ClassWriter { // fields for (StructField fd : cl.getFields()) { - int flags = fd.access_flags; - boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic"); - if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) - && !wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()))) { - - boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0; + boolean hide = fd.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) || + wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); + if (!hide) { + boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); if (isEnum) { if (enumfields) { bufstrwriter1.write(","); @@ -310,12 +305,11 @@ public class ClassWriter { // member classes for (ClassNode inner : node.nested) { if (inner.type == ClassNode.CLASS_MEMBER) { - StructClass innercl = inner.classStruct; - - boolean isSynthetic = - ((inner.access | innercl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || innercl.getAttributes().containsKey("Synthetic"); - if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) - && !wrapper.getHideMembers().contains(innercl.qualifiedName)) { + StructClass innerCl = inner.classStruct; + boolean isSynthetic = (inner.access & CodeConstants.ACC_SYNTHETIC) != 0 || innerCl.isSynthetic(); + boolean hide = isSynthetic && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) || + wrapper.getHideMembers().contains(innerCl.qualifiedName); + if (!hide) { writer.write(DecompilerContext.getNewLineSeparator()); classToJava(inner, writer, indent + 1); } @@ -347,7 +341,7 @@ public class ClassWriter { ClassWrapper wrapper = node.wrapper; StructClass cl = wrapper.getClassStruct(); - int flags = node.type == ClassNode.CLASS_ROOT ? cl.access_flags : node.access; + int flags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access; boolean isInterface = (flags & CodeConstants.ACC_INTERFACE) != 0; boolean isAnnotation = (flags & CodeConstants.ACC_ANNOTATION) != 0; boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0; @@ -486,8 +480,7 @@ public class ClassWriter { String indstr = InterpreterUtil.getIndentString(indent); - boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0; - int flags = fd.access_flags; + boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE); if (interceptor != null) { String oldname = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor()); @@ -515,8 +508,8 @@ public class ClassWriter { writer.write(DecompilerContext.getNewLineSeparator()); } - boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic"); - boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0; + boolean isSynthetic = fd.isSynthetic(); + boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); if (isSynthetic) { writer.write(indstr); @@ -529,7 +522,7 @@ public class ClassWriter { if (!isEnum) { for (int i = 0; i < modval_field.length; i++) { if (!isInterface || !mod_notinterface_fields.contains(modval_field[i])) { - if ((flags & modval_field[i]) != 0) { + if (fd.hasModifier(modval_field[i])) { writer.write(modstr_field[i]); } } @@ -559,7 +552,7 @@ public class ClassWriter { writer.write(fd.getName()); Exprent initializer; - if ((flags & CodeConstants.ACC_STATIC) != 0) { + if (fd.hasModifier(CodeConstants.ACC_STATIC)) { initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); } else { @@ -577,7 +570,7 @@ public class ClassWriter { writer.write(initializer.toJava(indent)); } } - else if ((flags & CodeConstants.ACC_FINAL) != 0 && (flags & CodeConstants.ACC_STATIC) != 0) { + else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) { StructConstantValueAttribute attr = (StructConstantValueAttribute)fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE); if (attr != null) { @@ -704,9 +697,9 @@ public class ClassWriter { MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth); - boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0; - boolean isAnnotation = (cl.access_flags & CodeConstants.ACC_ANNOTATION) != 0; - boolean isEnum = (cl.access_flags & CodeConstants.ACC_ENUM) != 0 && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); + boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE); + boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION); + boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); boolean isDeprecated = mt.getAttributes().containsKey("Deprecated"); String indstr = InterpreterUtil.getIndentString(indent); @@ -721,9 +714,8 @@ public class ClassWriter { if ((flags & CodeConstants.ACC_NATIVE) != 0) { flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp } - if ("".equals(mt.getName())) { - flags &= CodeConstants.ACC_STATIC; // ingnore all modifiers except 'static' in a static initializer + flags &= CodeConstants.ACC_STATIC; // ignore all modifiers except 'static' in a static initializer } if (interceptor != null) { @@ -816,7 +808,7 @@ public class ClassWriter { if (!clinit && !dinit) { - boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC); // formal type parameters if (descriptor != null && !descriptor.fparameters.isEmpty()) { @@ -900,8 +892,7 @@ public class ClassWriter { if (descriptor != null) { GenericType partype = descriptor.params.get(i); - boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0 - && partype.arraydim > 0); + boolean isVarArgs = (i == lastparam_index && mt.hasModifier(CodeConstants.ACC_VARARGS) && partype.arraydim > 0); if (isVarArgs) { partype.arraydim--; @@ -922,8 +913,7 @@ public class ClassWriter { else { VarType partype = md.params[i].copy(); - boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0 - && partype.arraydim > 0); + boolean isVarArgs = (i == lastparam_index && mt.hasModifier(CodeConstants.ACC_VARARGS) && partype.arraydim > 0); if (isVarArgs) { partype.decArrayDim(); diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index b822021..a16e4e0 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -139,7 +139,7 @@ public class ClassesProcessor { } ClassNode node = new ClassNode(ClassNode.CLASS_ROOT, cl); - node.access = cl.access_flags; + node.access = cl.getAccessFlags(); mapRootClasses.put(cl.qualifiedName, node); } } @@ -394,12 +394,9 @@ public class ClassesProcessor { anonimousClassType = new VarType(lambda_class_name, true); boolean is_method_reference = (content_class_name != classStruct.qualifiedName); - StructMethod mt = null; - if (!is_method_reference) { // content method in the same class, check synthetic flag - mt = classStruct.getMethod(content_method_name, content_method_descriptor); - is_method_reference = !((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 || - mt.getAttributes().containsKey("Synthetic")); // if not synthetic -> method reference + StructMethod mt = classStruct.getMethod(content_method_name, content_method_descriptor); + is_method_reference = !mt.isSynthetic(); // if not synthetic -> method reference } lambda_information.is_method_reference = is_method_reference; diff --git a/src/org/jetbrains/java/decompiler/main/EnumProcessor.java b/src/org/jetbrains/java/decompiler/main/EnumProcessor.java index 93746b7..fcdeaf1 100644 --- a/src/org/jetbrains/java/decompiler/main/EnumProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/EnumProcessor.java @@ -82,7 +82,7 @@ public class EnumProcessor { // hide dummy synthetic fields of enum constants for (StructField fd : cl.getFields()) { - if ((fd.access_flags & CodeConstants.ACC_ENUM) != 0) { + if (fd.hasModifier(CodeConstants.ACC_ENUM)) { Exprent initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); if (initializer != null && initializer.type == Exprent.EXPRENT_NEW) { @@ -97,10 +97,9 @@ public class EnumProcessor { } private static void hideDummyFieldInConstant(ClassWrapper wrapper) { - StructClass cl = wrapper.getClassStruct(); for (StructField fd : cl.getFields()) { - if ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0) { + if (fd.isSynthetic()) { FieldDescriptor descr = FieldDescriptor.parseDescriptor(fd.getDescriptor()); VarType ret = descr.type; diff --git a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java index 59689dc..aabea15 100644 --- a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java @@ -76,7 +76,7 @@ public class InitializerProcessor { FieldExprent fexpr = (FieldExprent)asexpr.getLeft(); if (fexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) { StructField structField = wrapper.getClassStruct().getField(fexpr.getName(), fexpr.getDescriptor().descriptorString); - if (structField != null && (structField.access_flags & CodeConstants.ACC_FINAL) != 0) { + if (structField != null && structField.hasModifier(CodeConstants.ACC_FINAL)) { action = 1; } } diff --git a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java index 2cadeae..cbaf227 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java +++ b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java @@ -123,7 +123,7 @@ public class ClassWrapper { } } else { - boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); int paramcount = 0; diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java index 3eec983..003bdc2 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -71,7 +71,7 @@ public class NestedClassProcessor { // ensure not-empty class name if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_MEMBER) && child.simpleName == null) { StructClass cl = child.classStruct; - if (((child.access | cl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic")) { + if ((child.access & CodeConstants.ACC_SYNTHETIC) != 0 || cl.isSynthetic()) { child.simpleName = "SyntheticClass_" + (++synthetics); } else { @@ -675,7 +675,7 @@ public class NestedClassProcessor { return null; } - boolean notsynth = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); + boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); // no loop at the begin DirectNode firstnode = graph.first; @@ -692,10 +692,8 @@ public class NestedClassProcessor { if (fd != null) { // local (== not inherited) field if (cl.qualifiedName.equals(left.getClassname()) && - (fd.access_flags & CodeConstants.ACC_FINAL) != 0 && - ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 || - fd.getAttributes().containsKey("Synthetic") || - (notsynth && (fd.access_flags & CodeConstants.ACC_PRIVATE) != 0))) { + fd.hasModifier(CodeConstants.ACC_FINAL) && + (fd.isSynthetic() || (noSynthFlag && fd.hasModifier(CodeConstants.ACC_PRIVATE)))) { field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString); break; } diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java b/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java index c1251a7..f61de85 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java @@ -32,26 +32,25 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; +import java.util.Map; public class NestedMemberAccess { private static final int METHOD_ACCESS_NORMAL = 1; - private static final int METHOD_ACCESS_FIELDGET = 2; - private static final int METHOD_ACCESS_FIELDSET = 3; + private static final int METHOD_ACCESS_FIELD_GET = 2; + private static final int METHOD_ACCESS_FIELD_SET = 3; private static final int METHOD_ACCESS_METHOD = 4; - private boolean notSetSync; - - private HashMap mapMethodType = new HashMap(); + private boolean noSynthFlag; + private Map mapMethodType = new HashMap(); public void propagateMemberAccess(ClassNode root) { - if (root.nested.isEmpty()) { return; } - notSetSync = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); + noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); computeMethodTypes(root); @@ -60,7 +59,6 @@ public class NestedMemberAccess { private void computeMethodTypes(ClassNode node) { - if (node.type == ClassNode.CLASS_LAMBDA) { return; } @@ -69,27 +67,24 @@ public class NestedMemberAccess { computeMethodTypes(nd); } - for (MethodWrapper meth : node.wrapper.getMethods()) { - computeMethodType(node, meth); + for (MethodWrapper method : node.wrapper.getMethods()) { + computeMethodType(node, method); } } - private void computeMethodType(ClassNode node, MethodWrapper meth) { - + private void computeMethodType(ClassNode node, MethodWrapper method) { int type = METHOD_ACCESS_NORMAL; - if (meth.root != null) { - - DirectGraph graph = meth.getOrBuildGraph(); + if (method.root != null) { + DirectGraph graph = method.getOrBuildGraph(); - int flags = meth.methodStruct.getAccessFlags(); - if (((flags & CodeConstants.ACC_SYNTHETIC) != 0 || meth.methodStruct.getAttributes().containsKey("Synthetic") || notSetSync) && - (flags & CodeConstants.ACC_STATIC) != 0) { + StructMethod mt = method.methodStruct; + if ((noSynthFlag || mt.isSynthetic()) && mt.hasModifier(CodeConstants.ACC_STATIC)) { if (graph.nodes.size() == 2) { // incl. dummy exit node if (graph.first.exprents.size() == 1) { Exprent exprent = graph.first.exprents.get(0); - MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor()); + MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(mt.getDescriptor()); int parcount = mtdesc.params.length; Exprent exprCore = exprent; @@ -109,7 +104,7 @@ public class NestedMemberAccess { if (fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field if (fexpr.isStatic() || (fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) { - type = METHOD_ACCESS_FIELDGET; + type = METHOD_ACCESS_FIELD_GET; } } } @@ -118,7 +113,7 @@ public class NestedMemberAccess { if (parcount == 1) { // this or final variable if (((VarExprent)exprCore).getIndex() != 0) { - type = METHOD_ACCESS_FIELDGET; + type = METHOD_ACCESS_FIELD_GET; } } @@ -136,7 +131,7 @@ public class NestedMemberAccess { if (fexpras.isStatic() || (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) { if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) { - type = METHOD_ACCESS_FIELDSET; + type = METHOD_ACCESS_FIELD_SET; } } } @@ -179,7 +174,7 @@ public class NestedMemberAccess { if (exprentFirst.type == Exprent.EXPRENT_ASSIGNMENT && exprentSecond.type == Exprent.EXPRENT_EXIT) { - MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor()); + MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(mt.getDescriptor()); int parcount = mtdesc.params.length; AssignmentExprent asexpr = (AssignmentExprent)exprentFirst; @@ -196,7 +191,7 @@ public class NestedMemberAccess { if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) { if (exexpr.getValue().type == Exprent.EXPRENT_VAR && ((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) { - type = METHOD_ACCESS_FIELDSET; + type = METHOD_ACCESS_FIELD_SET; } } } @@ -211,10 +206,10 @@ public class NestedMemberAccess { } if (type != METHOD_ACCESS_NORMAL) { - mapMethodType.put(meth, type); + mapMethodType.put(method, type); } else { - mapMethodType.remove(meth); + mapMethodType.remove(method); } } @@ -365,7 +360,7 @@ public class NestedMemberAccess { Exprent retexprent = null; switch (type) { - case METHOD_ACCESS_FIELDGET: + case METHOD_ACCESS_FIELD_GET: ExitExprent exsource = (ExitExprent)source; if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this VarExprent var = (VarExprent)exsource.getValue(); @@ -393,7 +388,7 @@ public class NestedMemberAccess { retexprent = ret; } break; - case METHOD_ACCESS_FIELDSET: + case METHOD_ACCESS_FIELD_SET: AssignmentExprent ret; if (source.type == Exprent.EXPRENT_EXIT) { ExitExprent extex = (ExitExprent)source; @@ -440,7 +435,7 @@ public class NestedMemberAccess { if (node.type == ClassNode.CLASS_ROOT || (node.access & CodeConstants.ACC_STATIC) != 0) { StructMethod mt = methsource.methodStruct; - if ((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) == 0 && !mt.getAttributes().containsKey("Synthetic")) { + if (!mt.isSynthetic()) { hide = false; } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java index 9934298..0f5141a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java @@ -82,7 +82,7 @@ public class IdeaNotNullHelper { if (first_param.type == Exprent.EXPRENT_VAR) { VarExprent var = (VarExprent)first_param; - boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); VBStyleCollection attributes = mt.getAttributes(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java index 33d30e9..6c6b1f3 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java @@ -109,43 +109,40 @@ public class AssignmentExprent extends Exprent { VarType leftType = left.getExprType(); VarType rightType = right.getExprType(); - String res = right.toJava(indent); - - if (condtype == CONDITION_NONE && - !leftType.isSuperset(rightType) && - (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) { - if (right.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) { - res = "(" + res + ")"; - } - - res = "(" + ExprProcessor.getCastTypeName(leftType) + ")" + res; - } - - StringBuilder buffer = new StringBuilder(); - - boolean finstat_init = false; + boolean fieldInStatInit = false; if (left.type == Exprent.EXPRENT_FIELD) { // first assignment to a final field. Field name without "this" in front of it FieldExprent field = (FieldExprent)left; - if (field.isStatic()) { - ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE)); - if (node != null) { - StructClass cl = node.classStruct; - StructField fd = cl.getField(field.getName(), field.getDescriptor().descriptorString); - - if (fd != null && (fd.access_flags & CodeConstants.ACC_FINAL) != 0) { - finstat_init = true; - } + ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE)); + if (node != null) { + StructClass cl = node.classStruct; + StructField fd = cl.getField(field.getName(), field.getDescriptor().descriptorString); + if (fd != null && field.isStatic() && fd.hasModifier(CodeConstants.ACC_FINAL)) { + fieldInStatInit = true; } } } - if (finstat_init) { + StringBuilder buffer = new StringBuilder(); + + if (fieldInStatInit) { buffer.append(((FieldExprent)left).getName()); } else { buffer.append(left.toJava(indent)); } + String res = right.toJava(indent); + + if (condtype == CONDITION_NONE && + !leftType.isSuperset(rightType) && + (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) { + if (right.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) { + res = "(" + res + ")"; + } + + res = "(" + ExprProcessor.getCastTypeName(leftType) + ")" + res; + } + buffer.append(condtype == CONDITION_NONE ? " = " : funceq[condtype]).append(res); return buffer.toString(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java index 1edebc9..04758dc 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -330,20 +330,19 @@ public class InvocationExprent extends Exprent { List sigFields = null; boolean isEnum = false; if (functype == TYP_INIT) { - ClassNode newnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); + ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); - if (newnode != null) { // own class - if (newnode.wrapper != null) { - sigFields = newnode.wrapper.getMethodWrapper("", stringDescriptor).signatureFields; + if (newNode != null) { // own class + if (newNode.wrapper != null) { + sigFields = newNode.wrapper.getMethodWrapper("", stringDescriptor).signatureFields; } else { - if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class + if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class sigFields = new ArrayList(Collections.nCopies(lstParameters.size(), (VarVersionPaar)null)); sigFields.set(0, new VarVersionPaar(-1, 0)); } } - isEnum = (newnode.classStruct.access_flags & CodeConstants.ACC_ENUM) != 0 && - DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); + isEnum = newNode.classStruct.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java index 2150f86..dbec793 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java @@ -487,8 +487,7 @@ public class SSAConstructorSparseEx { } private SFormsFastMapDirect createFirstMap(StructMethod mt) { - - boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java index 97b6448..fbd652c 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java @@ -756,8 +756,7 @@ public class SSAUConstructorSparseEx { } private SFormsFastMapDirect createFirstMap(StructMethod mt, RootStatement root) { - - boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java index 24207ef..fdd6cd5 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java @@ -53,7 +53,7 @@ public class VarDefinitionHelper { VarNamesCollector vc = DecompilerContext.getVarNamesCollector(); - boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java index d7d3d2e..a21d71f 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java @@ -49,7 +49,7 @@ public class VarTypeProcessor { StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD); // method descriptor - boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC); MethodDescriptor md = (MethodDescriptor)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java index 09d8def..06b7216 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java @@ -170,7 +170,7 @@ public class VarVersionsProcessor { } } - boolean is_method_static = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0; + boolean is_method_static = mt.hasModifier(CodeConstants.ACC_STATIC); final HashMap mapMergedVersions = new HashMap(); diff --git a/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java b/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java index 546ece3..adff502 100644 --- a/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java +++ b/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java @@ -232,11 +232,10 @@ public class IdentifierConverter { StructMethod mt = methods.get(i); String key = methods.getKey(i); - int access_flags = mt.getAccessFlags(); - boolean isPrivate = ((access_flags & CodeConstants.ACC_PRIVATE) != 0); + boolean isPrivate = mt.hasModifier(CodeConstants.ACC_PRIVATE); String name = mt.getName(); - if (!cl.isOwn() || (access_flags & CodeConstants.ACC_NATIVE) != 0) { + if (!cl.isOwn() || mt.hasModifier(CodeConstants.ACC_NATIVE)) { // external and native methods must not be renamed if (!isPrivate) { names.put(key, name); @@ -426,8 +425,7 @@ public class IdentifierConverter { break; } else { - - boolean isInterface = ((clstr.access_flags & CodeConstants.ACC_INTERFACE) != 0); + boolean isInterface = clstr.hasModifier(CodeConstants.ACC_INTERFACE); boolean found_parent = false; if (isInterface) { diff --git a/src/org/jetbrains/java/decompiler/struct/ContextUnit.java b/src/org/jetbrains/java/decompiler/struct/ContextUnit.java index c942e76..44ec746 100644 --- a/src/org/jetbrains/java/decompiler/struct/ContextUnit.java +++ b/src/org/jetbrains/java/decompiler/struct/ContextUnit.java @@ -18,6 +18,7 @@ package org.jetbrains.java.decompiler.struct; import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader.Link; +import org.jetbrains.java.decompiler.util.DataInputFullStream; import java.io.IOException; import java.util.ArrayList; @@ -98,7 +99,15 @@ public class ContextUnit { List lstClasses = new ArrayList(); for (StructClass cl : classes) { String oldname = cl.qualifiedName; - StructClass newcl = new StructClass(loader.getClassStream(oldname), cl.isOwn(), loader); + + StructClass newcl; + DataInputFullStream in = loader.getClassStream(oldname); + try { + newcl = new StructClass(in, cl.isOwn(), loader); + } + finally { + in.close(); + } lstClasses.add(newcl); diff --git a/src/org/jetbrains/java/decompiler/struct/StructClass.java b/src/org/jetbrains/java/decompiler/struct/StructClass.java index 78e941d..9afe081 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructClass.java +++ b/src/org/jetbrains/java/decompiler/struct/StructClass.java @@ -16,7 +16,6 @@ package org.jetbrains.java.decompiler.struct; import org.jetbrains.java.decompiler.code.CodeConstants; -import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; @@ -24,272 +23,127 @@ import org.jetbrains.java.decompiler.util.DataInputFullStream; import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.VBStyleCollection; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; /* - ClassFile { - u4 magic; - u2 minor_version; - u2 major_version; - u2 constant_pool_count; - cp_info constant_pool[constant_pool_count-1]; - u2 access_flags; - u2 this_class; - u2 super_class; - u2 interfaces_count; - u2 interfaces[interfaces_count]; - u2 fields_count; - field_info fields[fields_count]; - u2 methods_count; - method_info methods[methods_count]; - u2 attributes_count; - attribute_info attributes[attributes_count]; - } + class_file { + u4 magic; + u2 minor_version; + u2 major_version; + u2 constant_pool_count; + cp_info constant_pool[constant_pool_count-1]; + u2 access_flags; + u2 this_class; + u2 super_class; + u2 interfaces_count; + u2 interfaces[interfaces_count]; + u2 fields_count; + field_info fields[fields_count]; + u2 methods_count; + method_info methods[methods_count]; + u2 attributes_count; + attribute_info attributes[attributes_count]; + } */ +public class StructClass extends StructMember { -public class StructClass { - - // ***************************************************************************** - // public fields - // ***************************************************************************** - - public int minor_version; - - public int major_version; - - public int access_flags; - - public int this_class; + public final String qualifiedName; + public final PrimitiveConstant superClass; - public int super_class; - - public PrimitiveConstant thisClass; - - public PrimitiveConstant superClass; - - public String qualifiedName; - - - // ***************************************************************************** - // private fields - // ***************************************************************************** + private final boolean own; + private final LazyLoader loader; + private final int minorVersion; + private final int majorVersion; + private final int[] interfaces; + private final String[] interfaceNames; + private final VBStyleCollection fields; + private final VBStyleCollection methods; private ConstantPool pool; - private int[] interfaces; - - private String[] interfaceNames; - - private VBStyleCollection fields = new VBStyleCollection(); - - private VBStyleCollection methods = new VBStyleCollection(); - - private VBStyleCollection attributes = new VBStyleCollection(); - - private boolean own = true; - - private LazyLoader loader; - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - public StructClass(String filename, boolean own, LazyLoader loader) throws IOException { - this(new FileInputStream(filename), own, loader); - } - public StructClass(InputStream inStream, boolean own, LazyLoader loader) throws IOException { this(new DataInputFullStream(inStream), own, loader); } - public StructClass(DataInputFullStream inStream, boolean own, LazyLoader loader) throws IOException { + public StructClass(DataInputFullStream in, boolean own, LazyLoader loader) throws IOException { this.own = own; this.loader = loader; - initStruct(inStream); - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public boolean hasField(String name, String descriptor) { - return getField(name, descriptor) != null; - } - - public StructField getField(String name, String descriptor) { - return fields.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor)); - } - - public StructMethod getMethod(String key) { - return methods.getWithKey(key); - } - - public StructMethod getMethod(String name, String descriptor) { - return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor)); - } - - public void writeToFile(File file) throws IOException { - DataOutputStream out = new DataOutputStream(new FileOutputStream(file)); - writeToOutputStream(out); - out.close(); - } - - public void writeToOutputStream(DataOutputStream out) throws IOException { - - out.writeInt(0xCAFEBABE); - out.writeShort(minor_version); - out.writeShort(major_version); - - getPool().writeToOutputStream(out); - - out.writeShort(access_flags); - out.writeShort(this_class); - out.writeShort(super_class); - - out.writeShort(interfaces.length); - for (int i = 0; i < interfaces.length; i++) { - out.writeShort(interfaces[i]); - } - - out.writeShort(fields.size()); - for (int i = 0; i < fields.size(); i++) { - fields.get(i).writeToStream(out); - } - - out.writeShort(methods.size()); - for (int i = 0; i < methods.size(); i++) { - methods.get(i).writeToStream(out); - } - - out.writeShort(attributes.size()); - for (StructGeneralAttribute attr : attributes) { - attr.writeToStream(out); - } - } - - public String getInterface(int i) { - return interfaceNames[i]; - } - - public void releaseResources() { - if (loader != null) { - pool = null; - } - } - - // ***************************************************************************** - // private methods - // ***************************************************************************** - - private void initStruct(DataInputFullStream in) throws IOException { + in.discard(4); - in.skip(4); - - this.minor_version = in.readUnsignedShort(); - this.major_version = in.readUnsignedShort(); + minorVersion = in.readUnsignedShort(); + majorVersion = in.readUnsignedShort(); pool = new ConstantPool(in); - this.access_flags = in.readUnsignedShort(); - - this_class = in.readUnsignedShort(); - thisClass = pool.getPrimitiveConstant(this_class); - qualifiedName = thisClass.getString(); - - super_class = in.readUnsignedShort(); - superClass = pool.getPrimitiveConstant(super_class); + accessFlags = in.readUnsignedShort(); + int thisClassIdx = in.readUnsignedShort(); + int superClassIdx = in.readUnsignedShort(); + qualifiedName = pool.getPrimitiveConstant(thisClassIdx).getString(); + superClass = pool.getPrimitiveConstant(superClassIdx); // interfaces int length = in.readUnsignedShort(); - int[] arrInterfaces = new int[length]; - String[] arrInterfaceNames = new String[length]; - + interfaces = new int[length]; + interfaceNames = new String[length]; for (int i = 0; i < length; i++) { - arrInterfaces[i] = in.readUnsignedShort(); - arrInterfaceNames[i] = pool.getPrimitiveConstant(arrInterfaces[i]).getString(); + interfaces[i] = in.readUnsignedShort(); + interfaceNames[i] = pool.getPrimitiveConstant(interfaces[i]).getString(); } - this.interfaces = arrInterfaces; - this.interfaceNames = arrInterfaceNames; // fields - VBStyleCollection lstFields = new VBStyleCollection(); length = in.readUnsignedShort(); + fields = new VBStyleCollection(); for (int i = 0; i < length; i++) { - StructField field = new StructField(); - field.access_flags = in.readUnsignedShort(); - field.name_index = in.readUnsignedShort(); - field.descriptor_index = in.readUnsignedShort(); - - field.initStrings(pool, this_class); - - field.setAttributes(readAttributes(in)); - - lstFields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor())); + StructField field = new StructField(in, this); + fields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor())); } - this.fields = lstFields; // methods length = in.readUnsignedShort(); + methods = new VBStyleCollection(); for (int i = 0; i < length; i++) { - StructMethod meth = new StructMethod(in, own, this); - - //if(qualifiedName.endsWith("JUnitStatusLine") && !meth.getName().equals("onProcessStarted") && !meth.getName().startsWith("access")) { - //if(!meth.getName().equals("run")) { - // continue; - //} - - methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(meth.getName(), meth.getDescriptor())); + StructMethod method = new StructMethod(in, this); + methods.addWithKey(method, InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor())); } // attributes - this.attributes = readAttributes(in); - + attributes = readAttributes(in, pool); - // release memory - if (loader != null) { - pool = null; - } + releaseResources(); } - private VBStyleCollection readAttributes(DataInputFullStream in) throws IOException { + public boolean hasField(String name, String descriptor) { + return getField(name, descriptor) != null; + } - VBStyleCollection lstAttribute = new VBStyleCollection(); + public StructField getField(String name, String descriptor) { + return fields.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor)); + } - int length = in.readUnsignedShort(); - for (int i = 0; i < length; i++) { - int attr_nameindex = in.readUnsignedShort(); - String attrname = pool.getPrimitiveConstant(attr_nameindex).getString(); - - StructGeneralAttribute attr = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname); - - if (attr != null) { - byte[] arr = new byte[in.readInt()]; - in.readFull(arr); - attr.setInfo(arr); - - attr.initContent(pool); - lstAttribute.addWithKey(attr, attr.getName()); - } - else { - in.skip(in.readInt()); - } - } + public StructMethod getMethod(String key) { + return methods.getWithKey(key); + } - return lstAttribute; + public StructMethod getMethod(String name, String descriptor) { + return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor)); } + public String getInterface(int i) { + return interfaceNames[i]; + } - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** + public void releaseResources() { + if (loader != null) { + pool = null; + } + } public ConstantPool getPool() { - if (pool == null && loader != null) { pool = loader.loadPool(qualifiedName); } - return pool; } @@ -309,10 +163,6 @@ public class StructClass { return fields; } - public VBStyleCollection getAttributes() { - return attributes; - } - public boolean isOwn() { return own; } @@ -322,15 +172,15 @@ public class StructClass { } public boolean isVersionGE_1_5() { - return (major_version > 48 || (major_version == 48 && minor_version > 0)); // FIXME: check second condition + return (majorVersion > 48 || (majorVersion == 48 && minorVersion > 0)); // FIXME: check second condition } public boolean isVersionGE_1_7() { - return (major_version >= 51); + return (majorVersion >= 51); } public int getBytecodeVersion() { - switch (major_version) { + switch (majorVersion) { case 52: return CodeConstants.BYTECODE_JAVA_8; case 51: diff --git a/src/org/jetbrains/java/decompiler/struct/StructContext.java b/src/org/jetbrains/java/decompiler/struct/StructContext.java index ecca95a..da562e9 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructContext.java +++ b/src/org/jetbrains/java/decompiler/struct/StructContext.java @@ -19,6 +19,7 @@ import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver; import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; +import org.jetbrains.java.decompiler.util.DataInputFullStream; import java.io.File; import java.io.IOException; @@ -136,7 +137,15 @@ public class StructContext { if (filename.endsWith(".class")) { try { - StructClass cl = new StructClass(loader.getClassStream(file.getAbsolutePath(), null), isOwn, loader); + StructClass cl; + + DataInputFullStream in = loader.getClassStream(file.getAbsolutePath(), null); + try { + cl = new StructClass(in, isOwn, loader); + } + finally { + in.close(); + } classes.put(cl.qualifiedName, cl); unit.addClass(cl, filename); @@ -145,8 +154,8 @@ public class StructContext { isClass = true; } catch (IOException ex) { - DecompilerContext.getLogger() - .writeMessage("Invalid class file: " + (path.length() > 0 ? path + "/" : "") + filename, IFernflowerLogger.ERROR); + DecompilerContext.getLogger().writeMessage("Invalid class file: " + (path.length() > 0 ? path + "/" : "") + filename, + IFernflowerLogger.ERROR); } } diff --git a/src/org/jetbrains/java/decompiler/struct/StructField.java b/src/org/jetbrains/java/decompiler/struct/StructField.java index 4c0f25d..796d77f 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructField.java +++ b/src/org/jetbrains/java/decompiler/struct/StructField.java @@ -15,96 +15,44 @@ */ package org.jetbrains.java.decompiler.struct; -import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; -import org.jetbrains.java.decompiler.util.VBStyleCollection; +import org.jetbrains.java.decompiler.util.DataInputFullStream; -import java.io.DataOutputStream; import java.io.IOException; /* - field_info { - u2 access_flags; - u2 name_index; - u2 descriptor_index; - u2 attributes_count; - attribute_info attributes[attributes_count]; - } + field_info { + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + attribute_info attributes[attributes_count]; + } */ +public class StructField extends StructMember { -public class StructField { + private final String name; + private final String descriptor; - // ***************************************************************************** - // public fields - // ***************************************************************************** - public int access_flags; - public int name_index; - public int descriptor_index; + public StructField(DataInputFullStream in, StructClass clStruct) throws IOException { + accessFlags = in.readUnsignedShort(); + int nameIndex = in.readUnsignedShort(); + int descriptorIndex = in.readUnsignedShort(); - private String name; - private String descriptor; - - // ***************************************************************************** - // private fields - // ***************************************************************************** - - private VBStyleCollection attributes; - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - public StructField() { - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public void writeToStream(DataOutputStream out) throws IOException { - - out.writeShort(access_flags); - out.writeShort(name_index); - out.writeShort(descriptor_index); - - out.writeShort(attributes.size()); - for (StructGeneralAttribute attr : attributes) { - attr.writeToStream(out); - } - } - - public void initStrings(ConstantPool pool, int class_index) { - String[] values = pool.getClassElement(ConstantPool.FIELD, class_index, name_index, descriptor_index); + ConstantPool pool = clStruct.getPool(); + String[] values = pool.getClassElement(ConstantPool.FIELD, clStruct.qualifiedName, nameIndex, descriptorIndex); name = values[0]; descriptor = values[1]; - } - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public VBStyleCollection getAttributes() { - return attributes; - } - - public void setAttributes(VBStyleCollection attributes) { - this.attributes = attributes; - } - - public String getDescriptor() { - return descriptor; - } - - public void setDescriptor(String descriptor) { - this.descriptor = descriptor; + attributes = readAttributes(in, pool); } public String getName() { return name; } - public void setName(String name) { - this.name = name; + public String getDescriptor() { + return descriptor; } } diff --git a/src/org/jetbrains/java/decompiler/struct/StructMember.java b/src/org/jetbrains/java/decompiler/struct/StructMember.java new file mode 100644 index 0000000..f681e19 --- /dev/null +++ b/src/org/jetbrains/java/decompiler/struct/StructMember.java @@ -0,0 +1,87 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.decompiler.struct; + +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute; +import org.jetbrains.java.decompiler.struct.consts.ConstantPool; +import org.jetbrains.java.decompiler.util.DataInputFullStream; +import org.jetbrains.java.decompiler.util.VBStyleCollection; + +import java.io.IOException; + +public class StructMember { + + protected int accessFlags; + protected VBStyleCollection attributes; + + + public int getAccessFlags() { + return accessFlags; + } + + public VBStyleCollection getAttributes() { + return attributes; + } + + public boolean hasModifier(int modifier) { + return (accessFlags & modifier) == modifier; + } + + public boolean isSynthetic() { + return hasModifier(CodeConstants.ACC_SYNTHETIC) || attributes.containsKey(StructGeneralAttribute.ATTRIBUTE_SYNTHETIC); + } + + protected VBStyleCollection readAttributes(DataInputFullStream in, ConstantPool pool) throws IOException { + VBStyleCollection attributes = new VBStyleCollection(); + + int length = in.readUnsignedShort(); + for (int i = 0; i < length; i++) { + int nameIndex = in.readUnsignedShort(); + String name = pool.getPrimitiveConstant(nameIndex).getString(); + + StructGeneralAttribute attribute = readAttribute(in, pool, name); + + if (attribute != null) { + if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) && attributes.containsKey(name)) { + // merge all variable tables + StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name); + table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute); + } + else { + attributes.addWithKey(attribute, attribute.getName()); + } + } + } + + return attributes; + } + + protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException { + StructGeneralAttribute attribute = StructGeneralAttribute.createAttribute(name); + if (attribute == null) { + in.discard(in.readInt()); + } + else { + byte[] data = new byte[in.readInt()]; + in.readFull(data); + attribute.setInfo(data); + attribute.initContent(pool); + } + return attribute; + } +} diff --git a/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/src/org/jetbrains/java/decompiler/struct/StructMethod.java index e3de510..b055df6 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructMethod.java +++ b/src/org/jetbrains/java/decompiler/struct/StructMethod.java @@ -17,267 +17,106 @@ package org.jetbrains.java.decompiler.struct; import org.jetbrains.java.decompiler.code.*; import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; -import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; +import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; import org.jetbrains.java.decompiler.util.DataInputFullStream; import org.jetbrains.java.decompiler.util.VBStyleCollection; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import static org.jetbrains.java.decompiler.code.CodeConstants.*; + /* - method_info { - u2 access_flags; - u2 name_index; - u2 descriptor_index; - u2 attributes_count; - attribute_info attributes[attributes_count]; - } + method_info { + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + attribute_info attributes[attributes_count]; + } */ +public class StructMethod extends StructMember { -public class StructMethod implements CodeConstants { - - // ***************************************************************************** - // public fields - // ***************************************************************************** - - public int name_index; - - public int descriptor_index; - - // ***************************************************************************** - // private fields - // ***************************************************************************** - - private static final int[] opr_iconst = new int[]{-1, 0, 1, 2, 3, 4, 5}; - - private static final int[] opr_loadstore = new int[]{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}; - - private static final int[] opcs_load = new int[]{opc_iload, opc_lload, opc_fload, opc_dload, opc_aload}; - - private static final int[] opcs_store = new int[]{opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore}; - - - private int accessFlags; + private static final int[] opr_iconst = {-1, 0, 1, 2, 3, 4, 5}; + private static final int[] opr_loadstore = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}; + private static final int[] opcs_load = {opc_iload, opc_lload, opc_fload, opc_dload, opc_aload}; + private static final int[] opcs_store = {opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore}; - private VBStyleCollection attributes; - - private int localVariables; - - private int maxStack; - - private String name; - - private String descriptor; - - private InstructionSequence seq; + private final StructClass classStruct; + private final String name; + private final String descriptor; private boolean containsCode = false; + private int localVariables = 0; + private int codeLength = 0; + private int codeFullLength = 0; + private InstructionSequence seq; + private boolean expanded = false; - private StructClass classStruct; - - - // lazy properties - private boolean lazy; - - private boolean expanded; - - private byte[] code_content; - - private int code_length = 0; - - private int code_fulllength = 0; - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - public StructMethod(DataInputFullStream in, boolean own, StructClass clstruct) throws IOException { - this(in, true, own, clstruct); - } - - public StructMethod(DataInputFullStream in, boolean lazy, boolean own, StructClass clstruct) throws IOException { - this.lazy = lazy; - this.expanded = !lazy; - this.classStruct = clstruct; + public StructMethod(DataInputFullStream in, StructClass clStruct) throws IOException { + classStruct = clStruct; accessFlags = in.readUnsignedShort(); - name_index = in.readUnsignedShort(); - descriptor_index = in.readUnsignedShort(); - - ConstantPool pool = clstruct.getPool(); - - initStrings(pool, clstruct.this_class); - - VBStyleCollection lstAttribute = new VBStyleCollection(); - int len = in.readUnsignedShort(); - for (int i = 0; i < len; i++) { - - int attr_nameindex = in.readUnsignedShort(); - String attrname = pool.getPrimitiveConstant(attr_nameindex).getString(); - - if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) { - if (!own) { - // skip code in foreign classes - in.skip(8); - in.skip(in.readInt()); - in.skip(8 * in.readUnsignedShort()); - } - else { - containsCode = true; - - in.skip(4); - - maxStack = in.readUnsignedShort(); - localVariables = in.readUnsignedShort(); - - if (lazy) { - code_length = in.readInt(); + int nameIndex = in.readUnsignedShort(); + int descriptorIndex = in.readUnsignedShort(); - in.skip(code_length); - - int exc_length = in.readUnsignedShort(); - code_fulllength = code_length + exc_length * 8 + 2; - - in.skip(exc_length * 8); - } - else { - seq = parseBytecode(in, in.readInt(), pool); - } - } - - // code attributes - int length = in.readUnsignedShort(); - for (int j = 0; j < length; j++) { - int codeattr_nameindex = in.readUnsignedShort(); - String codeattrname = pool.getPrimitiveConstant(codeattr_nameindex).getString(); - - readAttribute(in, pool, lstAttribute, codeattr_nameindex, codeattrname); - } - } - else { - readAttribute(in, pool, lstAttribute, attr_nameindex, attrname); - } - } + ConstantPool pool = clStruct.getPool(); + String[] values = pool.getClassElement(ConstantPool.METHOD, clStruct.qualifiedName, nameIndex, descriptorIndex); + name = values[0]; + descriptor = values[1]; - attributes = lstAttribute; + attributes = readAttributes(in, pool); } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public void writeToStream(DataOutputStream out) throws IOException { - - out.writeShort(accessFlags); - out.writeShort(name_index); - out.writeShort(descriptor_index); - - out.writeShort(attributes.size()); - - for (StructGeneralAttribute attr : attributes) { - if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attr.getName())) { - out.writeShort(attr.getAttribute_name_index()); - - if (lazy && !expanded) { - out.writeInt(10 + code_content.length); - out.writeShort(maxStack); - out.writeShort(localVariables); - out.writeInt(code_length); - out.write(code_content); - } - else { - ByteArrayOutputStream codeout = new ByteArrayOutputStream(); - seq.writeCodeToStream(new DataOutputStream(codeout)); - - ByteArrayOutputStream excout = new ByteArrayOutputStream(); - seq.writeExceptionsToStream(new DataOutputStream(excout)); - - out.writeInt(10 + codeout.size() + excout.size()); - - out.writeShort(maxStack); - out.writeShort(localVariables); - out.writeInt(codeout.size()); - codeout.writeTo(out); - excout.writeTo(out); - } - // no attributes - out.writeShort(0); + @Override + protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException { + if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(name)) { + if (!classStruct.isOwn()) { + // skip code in foreign classes + in.discard(8); + in.discard(in.readInt()); + in.discard(8 * in.readUnsignedShort()); } else { - attr.writeToStream(out); + containsCode = true; + in.discard(6); + localVariables = in.readUnsignedShort(); + codeLength = in.readInt(); + in.discard(codeLength); + int exc_length = in.readUnsignedShort(); + in.discard(exc_length * 8); + codeFullLength = codeLength + exc_length * 8 + 2; } - } - } - - private static void readAttribute(DataInputFullStream in, - ConstantPool pool, - VBStyleCollection lstAttribute, - int attr_nameindex, - String attrname) throws IOException { - StructGeneralAttribute attribute = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname); + LazyLoader.skipAttributes(in); - if (attribute != null) { - attrname = attribute.getName(); - - byte[] arr = new byte[in.readInt()]; - in.readFull(arr); - attribute.setInfo(arr); - - attribute.initContent(pool); - - if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname) && - lstAttribute.containsKey(attrname)) { - // merge all variable tables - StructLocalVariableTableAttribute oldattr = (StructLocalVariableTableAttribute)lstAttribute.getWithKey(attrname); - oldattr.addLocalVariableTable((StructLocalVariableTableAttribute)attribute); - } - else { - lstAttribute.addWithKey(attribute, attribute.getName()); - } - } - else { - in.skip(in.readInt()); + return null; } - } - private void initStrings(ConstantPool pool, int class_index) { - String[] values = pool.getClassElement(ConstantPool.METHOD, class_index, name_index, descriptor_index); - name = values[0]; - descriptor = values[1]; + return super.readAttribute(in, pool, name); } public void expandData() throws IOException { - if (containsCode && lazy && !expanded) { - - byte[] codearr = classStruct.getLoader().loadBytecode(this, code_fulllength); - - seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(codearr)), code_length, classStruct.getPool()); + if (containsCode && !expanded) { + byte[] code = classStruct.getLoader().loadBytecode(this, codeFullLength); + seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(code)), codeLength, classStruct.getPool()); expanded = true; } } public void releaseResources() throws IOException { - if (containsCode && lazy && expanded) { + if (containsCode && expanded) { seq = null; expanded = false; } } - // ***************************************************************************** - // private methods - // ***************************************************************************** - private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException { - - VBStyleCollection collinstr = new VBStyleCollection(); + VBStyleCollection instructions = new VBStyleCollection(); int bytecode_version = classStruct.getBytecodeVersion(); @@ -370,7 +209,7 @@ public class StructMethod implements CodeConstants { case opc_invokedynamic: if (classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before operands.add(new Integer(in.readUnsignedShort())); - in.skip(2); + in.discard(2); group = GROUP_INVOCATION; i += 4; } @@ -420,7 +259,7 @@ public class StructMethod implements CodeConstants { case opc_invokeinterface: operands.add(new Integer(in.readUnsignedShort())); operands.add(new Integer(in.readUnsignedByte())); - in.skip(1); + in.discard(1); group = GROUP_INVOCATION; i += 4; break; @@ -430,7 +269,7 @@ public class StructMethod implements CodeConstants { i += 3; break; case opc_tableswitch: - in.skip((4 - (i + 1) % 4) % 4); + in.discard((4 - (i + 1) % 4) % 4); i += ((4 - (i + 1) % 4) % 4); // padding operands.add(new Integer(in.readInt())); i += 4; @@ -449,7 +288,7 @@ public class StructMethod implements CodeConstants { break; case opc_lookupswitch: - in.skip((4 - (i + 1) % 4) % 4); + in.discard((4 - (i + 1) % 4) % 4); i += ((4 - (i + 1) % 4) % 4); // padding operands.add(new Integer(in.readInt())); i += 4; @@ -483,7 +322,7 @@ public class StructMethod implements CodeConstants { Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops); - collinstr.addWithKey(instr, new Integer(offset)); + instructions.addWithKey(instr, new Integer(offset)); i++; } @@ -507,7 +346,7 @@ public class StructMethod implements CodeConstants { lstHandlers.add(handler); } - InstructionSequence seq = new FullInstructionSequence(collinstr, new ExceptionTable(lstHandlers)); + InstructionSequence seq = new FullInstructionSequence(instructions, new ExceptionTable(lstHandlers)); // initialize instructions int i = seq.length() - 1; @@ -524,41 +363,27 @@ public class StructMethod implements CodeConstants { return seq; } - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** + public StructClass getClassStruct() { + return classStruct; + } - public InstructionSequence getInstructionSequence() { - return seq; + public String getName() { + return name; } public String getDescriptor() { return descriptor; } - public String getName() { - return name; - } - - public int getAccessFlags() { - return accessFlags; + public boolean containsCode() { + return containsCode; } public int getLocalVariables() { return localVariables; } - public VBStyleCollection getAttributes() { - return attributes; - } - - public StructClass getClassStruct() { - return classStruct; - } - - public boolean containsCode() { - return containsCode; + public InstructionSequence getInstructionSequence() { + return seq; } } - - diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java index c52fcc7..53c02ec 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java @@ -17,9 +17,6 @@ package org.jetbrains.java.decompiler.struct.attr; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -38,30 +35,6 @@ public class StructExceptionsAttribute extends StructGeneralAttribute { } } - public void writeToStream(DataOutputStream out) throws IOException { - - out.writeShort(attribute_name_index); - - ByteArrayOutputStream codeout = new ByteArrayOutputStream(); - DataOutputStream dataout = new DataOutputStream(codeout); - - int len = throwsExceptions.size(); - dataout.writeShort(len); - - if (len > 0) { - info = new byte[len * 2]; - for (int i = 0, j = 0; i < len; i++, j += 2) { - int index = throwsExceptions.get(i).intValue(); - info[j] = (byte)(index >> 8); - info[j + 1] = (byte)(index & 0xFF); - } - dataout.write(info); - } - - out.writeInt(codeout.size()); - out.write(codeout.toByteArray()); - } - public String getExcClassname(int index, ConstantPool pool) { return pool.getPrimitiveConstant(throwsExceptions.get(index).intValue()).getString(); } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java index bd0596a..632575f 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java @@ -17,17 +17,13 @@ package org.jetbrains.java.decompiler.struct.attr; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; -import java.io.DataOutputStream; -import java.io.IOException; - /* - attribute_info { - u2 attribute_name_index; - u4 attribute_length; - u1 info[attribute_length]; - } + attribute_info { + u2 attribute_name_index; + u4 attribute_length; + u1 info[attribute_length]; + } */ - public class StructGeneralAttribute { public static final String ATTRIBUTE_CODE = "Code"; @@ -48,74 +44,51 @@ public class StructGeneralAttribute { public static final String ATTRIBUTE_SYNTHETIC = "Synthetic"; public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; - - // ***************************************************************************** - // private fields - // ***************************************************************************** - - protected int attribute_name_index; - - protected byte[] info; - protected String name; + protected byte[] info; - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public void writeToStream(DataOutputStream out) throws IOException { - out.writeShort(attribute_name_index); - out.writeInt(info.length); - if (info.length > 0) { - out.write(info); - } - } - - public void initContent(ConstantPool pool) { - name = pool.getPrimitiveConstant(attribute_name_index).getString(); - } - - public static StructGeneralAttribute getMatchingAttributeInstance(int nameindex, String attrname) { + public static StructGeneralAttribute createAttribute(String name) { StructGeneralAttribute attr; - if (ATTRIBUTE_INNER_CLASSES.equals(attrname)) { + if (ATTRIBUTE_INNER_CLASSES.equals(name)) { attr = new StructInnerClassesAttribute(); } - else if (ATTRIBUTE_CONSTANT_VALUE.equals(attrname)) { + else if (ATTRIBUTE_CONSTANT_VALUE.equals(name)) { attr = new StructConstantValueAttribute(); } - else if (ATTRIBUTE_SIGNATURE.equals(attrname)) { + else if (ATTRIBUTE_SIGNATURE.equals(name)) { attr = new StructGenericSignatureAttribute(); } - else if (ATTRIBUTE_ANNOTATION_DEFAULT.equals(attrname)) { + else if (ATTRIBUTE_ANNOTATION_DEFAULT.equals(name)) { attr = new StructAnnDefaultAttribute(); } - else if (ATTRIBUTE_EXCEPTIONS.equals(attrname)) { + else if (ATTRIBUTE_EXCEPTIONS.equals(name)) { attr = new StructExceptionsAttribute(); } - else if (ATTRIBUTE_ENCLOSING_METHOD.equals(attrname)) { + else if (ATTRIBUTE_ENCLOSING_METHOD.equals(name)) { attr = new StructEnclosingMethodAttribute(); } - else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(attrname) || - ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(attrname)) { + else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(name) || + ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(name)) { attr = new StructAnnotationAttribute(); } - else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attrname) || - ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attrname)) { + else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(name) || + ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(name)) { attr = new StructAnnotationParameterAttribute(); } - else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attrname) || - ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attrname)) { + else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(name) || + ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(name)) { attr = new StructAnnotationTypeAttribute(); } - else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname)) { + else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name)) { attr = new StructLocalVariableTableAttribute(); } - else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(attrname)) { + else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(name)) { attr = new StructBootstrapMethodsAttribute(); } - else if (ATTRIBUTE_SYNTHETIC.equals(attrname) || ATTRIBUTE_DEPRECATED.equals(attrname)) { + else if (ATTRIBUTE_SYNTHETIC.equals(name) || + ATTRIBUTE_DEPRECATED.equals(name)) { attr = new StructGeneralAttribute(); } else { @@ -123,17 +96,11 @@ public class StructGeneralAttribute { return null; } - attr.setAttribute_name_index(nameindex); + attr.name = name; return attr; } - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public byte[] getInfo() { - return info; - } + public void initContent(ConstantPool pool) { } public void setInfo(byte[] info) { this.info = info; @@ -142,16 +109,4 @@ public class StructGeneralAttribute { public String getName() { return name; } - - public void setName(String name) { - this.name = name; - } - - public int getAttribute_name_index() { - return attribute_name_index; - } - - public void setAttribute_name_index(int attribute_name_index) { - this.attribute_name_index = attribute_name_index; - } } diff --git a/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java b/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java index 1b21828..d534e6d 100644 --- a/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java +++ b/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java @@ -21,9 +21,9 @@ import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor; import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.util.DataInputFullStream; import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -31,25 +31,14 @@ import java.util.List; public class ConstantPool { public static final int FIELD = 1; - public static final int METHOD = 2; - // ***************************************************************************** - // private fields - // ***************************************************************************** - private List pool = new ArrayList(); - private PoolInterceptor interceptor; - // ***************************************************************************** - // constructors - // ***************************************************************************** public ConstantPool(DataInputStream in) throws IOException { - int size = in.readUnsignedShort(); - int[] pass = new int[size]; // first dummy constant @@ -57,7 +46,6 @@ public class ConstantPool { // first pass: read the elements for (int i = 1; i < size; i++) { - byte tag = (byte)in.readUnsignedByte(); switch (tag) { @@ -106,11 +94,10 @@ public class ConstantPool { } } - // resolving complex pool elements - for (int pass_index = 1; pass_index <= 3; pass_index++) { + for (int passIndex = 1; passIndex <= 3; passIndex++) { for (int i = 1; i < size; i++) { - if (pass[i] == pass_index) { + if (pass[i] == passIndex) { pool.get(i).resolveConstant(this); } } @@ -120,23 +107,7 @@ public class ConstantPool { interceptor = DecompilerContext.getPoolInterceptor(); } - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public void writeToOutputStream(DataOutputStream out) throws IOException { - - out.writeShort(pool.size()); - for (int i = 1; i < pool.size(); i++) { - PooledConstant cnst = pool.get(i); - if (cnst != null) { - cnst.writeToStream(out); - } - } - } - - public static void skipPool(DataInputStream in) throws IOException { - + public static void skipPool(DataInputFullStream in) throws IOException { int size = in.readUnsignedShort(); for (int i = 1; i < size; i++) { @@ -151,20 +122,20 @@ public class ConstantPool { case CodeConstants.CONSTANT_InterfaceMethodref: case CodeConstants.CONSTANT_NameAndType: case CodeConstants.CONSTANT_InvokeDynamic: - in.skip(4); + in.discard(4); break; case CodeConstants.CONSTANT_Long: case CodeConstants.CONSTANT_Double: - in.skip(8); + in.discard(8); i++; break; case CodeConstants.CONSTANT_Class: case CodeConstants.CONSTANT_String: case CodeConstants.CONSTANT_MethodType: - in.skip(2); + in.discard(2); break; case CodeConstants.CONSTANT_MethodHandle: - in.skip(3); + in.discard(3); } } } @@ -173,27 +144,24 @@ public class ConstantPool { return pool.size(); } - public String[] getClassElement(int element_type, int class_index, int name_index, int descriptor_index) { - - String classname = ((PrimitiveConstant)getConstant(class_index)).getString(); - String elementname = ((PrimitiveConstant)getConstant(name_index)).getString(); - String descriptor = ((PrimitiveConstant)getConstant(descriptor_index)).getString(); + public String[] getClassElement(int elementType, String className, int nameIndex, int descriptorIndex) { + String elementName = ((PrimitiveConstant)getConstant(nameIndex)).getString(); + String descriptor = ((PrimitiveConstant)getConstant(descriptorIndex)).getString(); if (interceptor != null) { - String new_element = interceptor.getName(classname + " " + elementname + " " + descriptor); - - if (new_element != null) { - elementname = new_element.split(" ")[1]; + String newElement = interceptor.getName(className + " " + elementName + " " + descriptor); + if (newElement != null) { + elementName = newElement.split(" ")[1]; } - String new_descriptor = buildNewDescriptor(element_type == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref, - descriptor); - if (new_descriptor != null) { - descriptor = new_descriptor; + int type = elementType == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref; + String newDescriptor = buildNewDescriptor(type, descriptor); + if (newDescriptor != null) { + descriptor = newDescriptor; } } - return new String[]{elementname, descriptor}; + return new String[]{elementName, descriptor}; } public PooledConstant getConstant(int index) { @@ -205,9 +173,9 @@ public class ConstantPool { if (cn != null && interceptor != null) { if (cn.type == CodeConstants.CONSTANT_Class) { - String newname = buildNewClassname(cn.getString()); - if (newname != null) { - cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newname); + String newName = buildNewClassname(cn.getString()); + if (newName != null) { + cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newName); } } } @@ -218,33 +186,30 @@ public class ConstantPool { public LinkConstant getLinkConstant(int index) { LinkConstant ln = (LinkConstant)getConstant(index); - if (ln != null && interceptor != null) { - if (ln.type == CodeConstants.CONSTANT_Fieldref || - ln.type == CodeConstants.CONSTANT_Methodref || - ln.type == CodeConstants.CONSTANT_InterfaceMethodref) { - - String new_classname = buildNewClassname(ln.classname); - String new_element = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor); - String new_descriptor = buildNewDescriptor(ln.type, ln.descriptor); - - if (new_classname != null || new_element != null || new_descriptor != null) { - - ln = new LinkConstant(ln.type, new_classname == null ? ln.classname : new_classname, - new_element == null ? ln.elementname : new_element.split(" ")[1], - new_descriptor == null ? ln.descriptor : new_descriptor); - } + if (ln != null && interceptor != null && + (ln.type == CodeConstants.CONSTANT_Fieldref || + ln.type == CodeConstants.CONSTANT_Methodref || + ln.type == CodeConstants.CONSTANT_InterfaceMethodref)) { + String newClassName = buildNewClassname(ln.classname); + String newElement = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor); + String newDescriptor = buildNewDescriptor(ln.type, ln.descriptor); + + if (newClassName != null || newElement != null || newDescriptor != null) { + String className = newClassName == null ? ln.classname : newClassName; + String elementName = newElement == null ? ln.elementname : newElement.split(" ")[1]; + String descriptor = newDescriptor == null ? ln.descriptor : newDescriptor; + ln = new LinkConstant(ln.type, className, elementName, descriptor); } } return ln; } - private String buildNewClassname(String classname) { - - VarType vt = new VarType(classname, true); + private String buildNewClassname(String className) { + VarType vt = new VarType(className, true); - String newname = interceptor.getName(vt.value); - if (newname != null) { + String newName = interceptor.getName(vt.value); + if (newName != null) { StringBuilder buffer = new StringBuilder(); if (vt.arraydim > 0) { @@ -252,10 +217,10 @@ public class ConstantPool { buffer.append("["); } - buffer.append("L").append(newname).append(";"); + buffer.append("L").append(newName).append(";"); } else { - buffer.append(newname); + buffer.append(newName); } return buffer.toString(); @@ -265,17 +230,16 @@ public class ConstantPool { } private String buildNewDescriptor(int type, String descriptor) { - boolean updated = false; if (type == CodeConstants.CONSTANT_Fieldref) { FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor); - VarType ftype = fd.type; - if (ftype.type == CodeConstants.TYPE_OBJECT) { - String newclname = buildNewClassname(ftype.value); - if (newclname != null) { - ftype.value = newclname; + VarType fType = fd.type; + if (fType.type == CodeConstants.TYPE_OBJECT) { + String newClassName = buildNewClassname(fType.value); + if (newClassName != null) { + fType.value = newClassName; updated = true; } } @@ -285,14 +249,14 @@ public class ConstantPool { } } else { - MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor); - // params - for (VarType partype : md.params) { - if (partype.type == CodeConstants.TYPE_OBJECT) { - String newclname = buildNewClassname(partype.value); - if (newclname != null) { - partype.value = newclname; + + // parameters + for (VarType paramType : md.params) { + if (paramType.type == CodeConstants.TYPE_OBJECT) { + String newClassName = buildNewClassname(paramType.value); + if (newClassName != null) { + paramType.value = newClassName; updated = true; } } @@ -300,9 +264,9 @@ public class ConstantPool { // return value if (md.ret.type == CodeConstants.TYPE_OBJECT) { - String newclname = buildNewClassname(md.ret.value); - if (newclname != null) { - md.ret.value = newclname; + String newClassName = buildNewClassname(md.ret.value); + if (newClassName != null) { + md.ret.value = newClassName; updated = true; } } diff --git a/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java b/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java index 53269da..65a6213 100644 --- a/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java +++ b/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java @@ -65,7 +65,7 @@ public class DataPoint { MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); int k = 0; - if ((mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0) { + if (!mt.hasModifier(CodeConstants.ACC_STATIC)) { point.setVariable(k++, new VarType(CodeConstants.TYPE_OBJECT, 0, null)); } diff --git a/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java b/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java index 8673c21..f610900 100644 --- a/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java +++ b/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java @@ -24,11 +24,11 @@ import org.jetbrains.java.decompiler.util.DataInputFullStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import java.util.Map; public class LazyLoader { - private HashMap mapClassLinks = new HashMap(); - + private Map mapClassLinks = new HashMap(); private IBytecodeProvider provider; public LazyLoader(IBytecodeProvider provider) { @@ -47,98 +47,88 @@ public class LazyLoader { return mapClassLinks.get(classname); } - public ConstantPool loadPool(String classname) { - try { - DataInputFullStream in = getClassStream(classname); - if (in == null) { - return null; - } - - in.skip(8); + if (in == null) return null; - return new ConstantPool(in); + try { + in.discard(8); + return new ConstantPool(in); + } + finally { + in.close(); + } } catch (IOException ex) { throw new RuntimeException(ex); } } - public byte[] loadBytecode(StructMethod mt, int code_fulllength) { + public byte[] loadBytecode(StructMethod mt, int codeFullLength) { + String className = mt.getClassStruct().qualifiedName; try { + DataInputFullStream in = getClassStream(className); + if (in == null) return null; - DataInputFullStream in = getClassStream(mt.getClassStruct().qualifiedName); - if (in == null) { - return null; - } - - byte[] res = null; - - in.skip(8); - - ConstantPool pool = mt.getClassStruct().getPool(); - if (pool == null) { - pool = new ConstantPool(in); - } - else { - ConstantPool.skipPool(in); - } + try { + in.discard(8); - in.skip(2); - int this_class = in.readUnsignedShort(); - in.skip(2); - - // interfaces - in.skip(in.readUnsignedShort() * 2); - - // fields - int size = in.readUnsignedShort(); - for (int i = 0; i < size; i++) { - in.skip(6); - skipAttributes(in); - } - - // methods - size = in.readUnsignedShort(); - for (int i = 0; i < size; i++) { - in.skip(2); + ConstantPool pool = mt.getClassStruct().getPool(); + if (pool == null) { + pool = new ConstantPool(in); + } + else { + ConstantPool.skipPool(in); + } - int name_index = in.readUnsignedShort(); - int descriptor_index = in.readUnsignedShort(); + in.discard(6); - String[] elem_arr = pool.getClassElement(ConstantPool.METHOD, this_class, name_index, descriptor_index); - String name = elem_arr[0]; + // interfaces + in.discard(in.readUnsignedShort() * 2); - if (mt.getName().equals(name)) { - String descriptor = elem_arr[1]; - if (mt.getDescriptor().equals(descriptor)) { + // fields + int size = in.readUnsignedShort(); + for (int i = 0; i < size; i++) { + in.discard(6); + skipAttributes(in); + } - int len = in.readUnsignedShort(); - for (int j = 0; j < len; j++) { + // methods + size = in.readUnsignedShort(); + for (int i = 0; i < size; i++) { + in.discard(2); - int attr_nameindex = in.readUnsignedShort(); - String attrname = pool.getPrimitiveConstant(attr_nameindex).getString(); + int nameIndex = in.readUnsignedShort(); + int descriptorIndex = in.readUnsignedShort(); - if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) { - in.skip(12); + String[] values = pool.getClassElement(ConstantPool.METHOD, className, nameIndex, descriptorIndex); + if (!mt.getName().equals(values[0]) || !mt.getDescriptor().equals(values[1])) { + skipAttributes(in); + continue; + } - res = new byte[code_fulllength]; - in.readFull(res); - return res; - } - else { - in.skip(in.readInt()); - } + int attrSize = in.readUnsignedShort(); + for (int j = 0; j < attrSize; j++) { + int attrNameIndex = in.readUnsignedShort(); + String attrName = pool.getPrimitiveConstant(attrNameIndex).getString(); + if (!StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrName)) { + in.discard(in.readInt()); + continue; } - return null; + in.discard(12); + byte[] code = new byte[codeFullLength]; + in.readFull(code); + return code; } - } - skipAttributes(in); + break; + } + } + finally { + in.close(); } return null; @@ -148,39 +138,38 @@ public class LazyLoader { } } - public DataInputFullStream getClassStream(String externPath, String internPath) throws IOException { - InputStream instream = provider.getBytecodeStream(externPath, internPath); - return instream == null ? null : new DataInputFullStream(instream); + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + public DataInputFullStream getClassStream(String externalPath, String internalPath) throws IOException { + InputStream stream = provider.getBytecodeStream(externalPath, internalPath); + return stream == null ? null : new DataInputFullStream(stream); } public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException { Link link = mapClassLinks.get(qualifiedClassName); - return link == null ? null : getClassStream(link.externPath, link.internPath); + return link == null ? null : getClassStream(link.externalPath, link.internalPath); } - private static void skipAttributes(DataInputFullStream in) throws IOException { - + public static void skipAttributes(DataInputFullStream in) throws IOException { int length = in.readUnsignedShort(); for (int i = 0; i < length; i++) { - in.skip(2); - in.skip(in.readInt()); + in.discard(2); + in.discard(in.readInt()); } } public static class Link { - public static final int CLASS = 1; public static final int ENTRY = 2; public int type; - public String externPath; - public String internPath; + public String externalPath; + public String internalPath; - public Link(int type, String externPath, String internPath) { + public Link(int type, String externalPath, String internalPath) { this.type = type; - this.externPath = externPath; - this.internPath = internPath; + this.externalPath = externalPath; + this.internalPath = internalPath; } } } diff --git a/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java b/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java index 0ed20dc..79e8c1d 100644 --- a/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java +++ b/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java @@ -25,20 +25,19 @@ public class DataInputFullStream extends DataInputStream { super(in); } - public final int readFull(byte[] b) throws IOException { - + public int readFull(byte[] b) throws IOException { int length = b.length; - byte[] btemp = new byte[length]; + byte[] temp = new byte[length]; int pos = 0; - int bytes_read = -1; + int bytes_read; while (true) { - bytes_read = read(btemp, 0, length - pos); + bytes_read = read(temp, 0, length - pos); if (bytes_read == -1) { return -1; } - System.arraycopy(btemp, 0, b, pos, bytes_read); + System.arraycopy(temp, 0, b, pos, bytes_read); pos += bytes_read; if (pos == length) { break; @@ -47,4 +46,10 @@ public class DataInputFullStream extends DataInputStream { return length; } + + public void discard(int n) throws IOException { + if (super.skip(n) != n) { + throw new IOException("Skip failed"); + } + } } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 291c0e7..02fb612 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -33,9 +33,11 @@ public class SingleClassesTest { @Before public void setUp() throws IOException { + //noinspection SSBasedInspection tempDir = File.createTempFile("decompiler_test_", "_dir"); assertTrue(tempDir.delete()); assertTrue(tempDir.mkdirs()); + decompiler = new ConsoleDecompiler(new HashMap() {{ put(IFernflowerPreferences.LOG_LEVEL, "warn"); put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1");