From 4e284c4ce2d7b5448895e27d603375277c886f7c Mon Sep 17 00:00:00 2001 From: Skylot Date: Thu, 2 May 2013 18:22:40 +0400 Subject: [PATCH] Use chars instead strings, code refactoring --- src/main/java/jadx/codegen/ClassGen.java | 22 ++++++------- src/main/java/jadx/codegen/CodeWriter.java | 2 +- src/main/java/jadx/codegen/InsnGen.java | 31 ++++++++----------- src/main/java/jadx/codegen/MethodGen.java | 4 +-- src/main/java/jadx/codegen/RegionGen.java | 2 +- src/main/java/jadx/codegen/TypeGen.java | 1 + src/main/java/jadx/dex/info/FieldInfo.java | 2 +- .../jadx/dex/instructions/IndexInsnNode.java | 2 +- .../jadx/dex/instructions/args/ArgType.java | 7 ++--- .../jadx/dex/instructions/args/InsnArg.java | 4 +++ .../dex/instructions/args/RegisterArg.java | 1 + .../jadx/dex/instructions/args/TypedVar.java | 10 +++--- src/main/java/jadx/dex/nodes/DexNode.java | 2 +- src/main/java/jadx/dex/nodes/InsnNode.java | 2 +- src/main/java/jadx/dex/nodes/MethodNode.java | 3 +- .../jadx/dex/visitors/BlockMakerVisitor.java | 25 +++++++-------- .../dex/visitors/BlockProcessingHelper.java | 5 +-- .../dex/visitors/ConstInlinerVisitor.java | 2 +- .../jadx/dex/visitors/DotGraphVisitor.java | 4 +-- .../dex/visitors/MethodInlinerVisitor.java | 3 +- src/main/java/jadx/utils/BlockUtils.java | 9 ++---- src/main/java/jadx/utils/StringUtils.java | 2 +- src/main/java/jadx/utils/Utils.java | 2 +- 23 files changed, 70 insertions(+), 77 deletions(-) diff --git a/src/main/java/jadx/codegen/ClassGen.java b/src/main/java/jadx/codegen/ClassGen.java index 2f99f0c63..eba925b6b 100644 --- a/src/main/java/jadx/codegen/ClassGen.java +++ b/src/main/java/jadx/codegen/ClassGen.java @@ -55,7 +55,7 @@ public class ClassGen { CodeWriter clsCode = new CodeWriter(); if (!"".equals(cls.getPackage())) { - clsCode.add("package ").add(cls.getPackage()).add(";"); + clsCode.add("package ").add(cls.getPackage()).add(';'); clsCode.endl(); } @@ -66,7 +66,7 @@ public class ClassGen { Collections.sort(sortImports); for (String imp : sortImports) { - clsCode.startLine("import ").add(imp).add(";"); + clsCode.startLine("import ").add(imp).add(';'); } clsCode.endl(); @@ -165,7 +165,7 @@ public class ClassGen { } public void makeClassBody(CodeWriter clsCode) throws CodegenException { - clsCode.add("{"); + clsCode.add('{'); CodeWriter mthsCode = makeMethods(clsCode, cls.getMethods()); clsCode.add(makeFields(clsCode, cls, cls.getFields())); @@ -174,7 +174,7 @@ public class ClassGen { clsCode.add(makeInnerClasses(cls, clsCode.getIndent())); } clsCode.add(mthsCode); - clsCode.startLine("}"); + clsCode.startLine('}'); } private CodeWriter makeInnerClasses(ClassNode cls2, int indent) throws CodegenException { @@ -190,7 +190,7 @@ public class ClassGen { return innerClsCode; } - private CodeWriter makeMethods(CodeWriter clsCode, List mthList) throws CodegenException { + private CodeWriter makeMethods(CodeWriter clsCode, List mthList) { CodeWriter code = new CodeWriter(clsCode.getIndent() + 1); for (Iterator it = mthList.iterator(); it.hasNext();) { MethodNode mth = it.next(); @@ -208,7 +208,7 @@ public class ClassGen { code.add(" default ").add(v); } } - code.add(";"); + code.add(';'); } else { if (mth.isNoCode()) continue; @@ -217,7 +217,7 @@ public class ClassGen { mthGen.addDefinition(code); code.add(" {"); code.add(mthGen.makeInstructions(code.getIndent())); - code.startLine("}"); + code.startLine('}'); } } catch (Throwable e) { String msg = ErrorsCounter.methodError(mth, "Method generation error", e); @@ -268,7 +268,7 @@ public class ClassGen { annotationGen.addForField(code, f); code.startLine(f.getAccessFlags().makeString()); code.add(TypeGen.translate(this, f.getType())); - code.add(" "); + code.add(' '); code.add(f.getName()); FieldValueAttr fv = (FieldValueAttr) f.getAttributes().get(AttributeType.FIELD_VALUE); if (fv != null) { @@ -279,7 +279,7 @@ public class ClassGen { code.add(annotationGen.encValueToString(fv.getValue())); } } - code.add(";"); + code.add(';'); } if (fields.size() != 0) code.endl(); @@ -299,7 +299,7 @@ public class ClassGen { if (generics != null) { StringBuilder sb = new StringBuilder(); sb.append(baseClass); - sb.append("<"); + sb.append('<'); int len = generics.length; for (int i = 0; i < len; i++) { if (i != 0) { @@ -311,7 +311,7 @@ public class ClassGen { else sb.append('?'); } - sb.append(">"); + sb.append('>'); return sb.toString(); } else { return baseClass; diff --git a/src/main/java/jadx/codegen/CodeWriter.java b/src/main/java/jadx/codegen/CodeWriter.java index 6138d4910..1802e4d18 100644 --- a/src/main/java/jadx/codegen/CodeWriter.java +++ b/src/main/java/jadx/codegen/CodeWriter.java @@ -13,7 +13,7 @@ public class CodeWriter { private static final int MAX_FILENAME_LENGTH = 128; public static final String NL = System.getProperty("line.separator"); - public static final String INDENT = "\t"; + private static final String INDENT = "\t"; private StringBuilder buf = new StringBuilder(); private String indentStr; diff --git a/src/main/java/jadx/codegen/InsnGen.java b/src/main/java/jadx/codegen/InsnGen.java index fedbe794b..03535fd53 100644 --- a/src/main/java/jadx/codegen/InsnGen.java +++ b/src/main/java/jadx/codegen/InsnGen.java @@ -84,20 +84,15 @@ public class InsnGen { } public String assignVar(InsnNode insn) { - try { - RegisterArg arg = insn.getResult(); - if (insn.getAttributes().contains(AttributeType.DECLARE_VARIABLE)) { - return declareVar(arg); - } else { - return mgen.makeArgName(arg); - } - } catch (CodegenException e) { - LOG.error("Assign var codegen error", e); - return ""; + RegisterArg arg = insn.getResult(); + if (insn.getAttributes().contains(AttributeType.DECLARE_VARIABLE)) { + return declareVar(arg); + } else { + return mgen.makeArgName(arg); } } - public String declareVar(RegisterArg arg) throws CodegenException { + public String declareVar(RegisterArg arg) { return useType(arg.getType()) + " " + mgen.assignArg(arg); } @@ -237,8 +232,8 @@ public class InsnGen { break; case INSTANCE_OF: - code.add("(").add(arg(insn, 0)).add(" instanceof ") - .add(useType((ArgType) ((IndexInsnNode) insn).getIndex())).add(")"); + code.add('(').add(arg(insn, 0)).add(" instanceof ") + .add(useType((ArgType) ((IndexInsnNode) insn).getIndex())).add(')'); break; case CONSTRUCTOR: @@ -296,7 +291,7 @@ public class InsnGen { case MONITOR_ENTER: if (isFallback()) { - code.add("monitor-enter(").add(arg(insn.getArg(0))).add(")"); + code.add("monitor-enter(").add(arg(insn.getArg(0))).add(')'); } else { state.add(InsnGenState.SKIP); } @@ -304,7 +299,7 @@ public class InsnGen { case MONITOR_EXIT: if (isFallback()) { - code.add("monitor-exit(").add(arg(insn.getArg(0))).add(")"); + code.add("monitor-exit(").add(arg(insn.getArg(0))).add(')'); } else { state.add(InsnGenState.SKIP); } @@ -358,7 +353,7 @@ public class InsnGen { } code.startLine("default: goto " + MethodGen.getLabelName(sw.getDefaultCaseOffset()) + ";"); code.decIndent(); - code.startLine("}"); + code.startLine('}'); state.add(InsnGenState.NO_SEMICOLON); break; @@ -376,13 +371,13 @@ public class InsnGen { private void filledNewArray(InsnNode insn, CodeWriter code) throws CodegenException { int c = insn.getArgsCount(); code.add("new ").add(useType(insn.getResult().getType())); - code.add("{"); + code.add('{'); for (int i = 0; i < c; i++) { code.add(arg(insn, i)); if (i + 1 < c) code.add(", "); } - code.add("}"); + code.add('}'); } private void fillArray(FillArrayOp insn, CodeWriter code) throws CodegenException { diff --git a/src/main/java/jadx/codegen/MethodGen.java b/src/main/java/jadx/codegen/MethodGen.java index 25e1f2772..bea58c385 100644 --- a/src/main/java/jadx/codegen/MethodGen.java +++ b/src/main/java/jadx/codegen/MethodGen.java @@ -133,7 +133,7 @@ public class MethodGen { } else { argsCode.add(TypeGen.translate(classGen, arg.getType())); } - argsCode.add(" "); + argsCode.add(' '); argsCode.add(makeArgName(arg)); i++; @@ -253,7 +253,7 @@ public class MethodGen { makeFallbackMethod(code, mth); code.decIndent(); - code.startLine("}"); + code.startLine('}'); code.startLine("*/"); } diff --git a/src/main/java/jadx/codegen/RegionGen.java b/src/main/java/jadx/codegen/RegionGen.java index 85525bd03..5d243d717 100644 --- a/src/main/java/jadx/codegen/RegionGen.java +++ b/src/main/java/jadx/codegen/RegionGen.java @@ -254,7 +254,7 @@ public class RegionGen extends InsnGen { code.startLine("} catch ("); code.add(handler.isCatchAll() ? "Throwable" : useClass(handler.getCatchType())); code.add(' '); - code.add(arg(handler.getArg())); + code.add(mgen.assignArg(handler.getArg())); code.add(") {"); makeRegionIndent(code, region); } diff --git a/src/main/java/jadx/codegen/TypeGen.java b/src/main/java/jadx/codegen/TypeGen.java index b427bb346..2939a53b6 100644 --- a/src/main/java/jadx/codegen/TypeGen.java +++ b/src/main/java/jadx/codegen/TypeGen.java @@ -22,6 +22,7 @@ public class TypeGen { return stype.getLongName(); } + @Deprecated public static String shortString(ArgType type) { final PrimitiveType stype = type.getPrimitiveType(); if (stype == null) diff --git a/src/main/java/jadx/dex/info/FieldInfo.java b/src/main/java/jadx/dex/info/FieldInfo.java index 923853bdf..26b0f6fae 100644 --- a/src/main/java/jadx/dex/info/FieldInfo.java +++ b/src/main/java/jadx/dex/info/FieldInfo.java @@ -16,7 +16,7 @@ public class FieldInfo { return new FieldInfo(dex, index); } - protected FieldInfo(DexNode dex, int ind) { + private FieldInfo(DexNode dex, int ind) { FieldId field = dex.getFieldId(ind); this.name = dex.getString(field.getNameIndex()); this.type = dex.getType(field.getTypeIndex()); diff --git a/src/main/java/jadx/dex/instructions/IndexInsnNode.java b/src/main/java/jadx/dex/instructions/IndexInsnNode.java index 3691ebb3e..62ee6c38d 100644 --- a/src/main/java/jadx/dex/instructions/IndexInsnNode.java +++ b/src/main/java/jadx/dex/instructions/IndexInsnNode.java @@ -5,7 +5,7 @@ import jadx.utils.InsnUtils; public class IndexInsnNode extends InsnNode { - protected final Object index; + private final Object index; public IndexInsnNode(InsnType type, Object index, int argCount) { super(type, argCount); diff --git a/src/main/java/jadx/dex/instructions/args/ArgType.java b/src/main/java/jadx/dex/instructions/args/ArgType.java index 6241083f8..69093e595 100644 --- a/src/main/java/jadx/dex/instructions/args/ArgType.java +++ b/src/main/java/jadx/dex/instructions/args/ArgType.java @@ -587,10 +587,7 @@ public abstract class ArgType { return false; } // TODO: don't use toString - if (!toString().equals(obj.toString())) { - return false; - } - return true; - } + return toString().equals(obj.toString()); + } } diff --git a/src/main/java/jadx/dex/instructions/args/InsnArg.java b/src/main/java/jadx/dex/instructions/args/InsnArg.java index 078a2ead5..1ad168aa2 100644 --- a/src/main/java/jadx/dex/instructions/args/InsnArg.java +++ b/src/main/java/jadx/dex/instructions/args/InsnArg.java @@ -72,4 +72,8 @@ public abstract class InsnArg extends Typed { return false; } + public int getRegNum() { + throw new UnsupportedOperationException("Must be called from RegisterArg"); + } + } diff --git a/src/main/java/jadx/dex/instructions/args/RegisterArg.java b/src/main/java/jadx/dex/instructions/args/RegisterArg.java index e871afdc1..51b603ec3 100644 --- a/src/main/java/jadx/dex/instructions/args/RegisterArg.java +++ b/src/main/java/jadx/dex/instructions/args/RegisterArg.java @@ -17,6 +17,7 @@ public class RegisterArg extends InsnArg { this.regNum = rn; } + @Override public int getRegNum() { return regNum; } diff --git a/src/main/java/jadx/dex/instructions/args/TypedVar.java b/src/main/java/jadx/dex/instructions/args/TypedVar.java index 8444c50e6..76a5832c8 100644 --- a/src/main/java/jadx/dex/instructions/args/TypedVar.java +++ b/src/main/java/jadx/dex/instructions/args/TypedVar.java @@ -57,7 +57,7 @@ public class TypedVar { @Override public int hashCode() { - return type.hashCode() * 31 + ((name == null) ? 0 : name.hashCode()); + return type.hashCode() * 31 + (name == null ? 0 : name.hashCode()); } @Override @@ -66,12 +66,12 @@ public class TypedVar { if (obj == null) return false; if (getClass() != obj.getClass()) return false; TypedVar other = (TypedVar) obj; + if (!type.equals(other.type)) return false; if (name == null) { if (other.name != null) return false; - } else if (!name.equals(other.name)) return false; - if (type == null) { - if (other.type != null) return false; - } else if (!type.equals(other.type)) return false; + } else if (!name.equals(other.name)) { + return false; + } return true; } diff --git a/src/main/java/jadx/dex/nodes/DexNode.java b/src/main/java/jadx/dex/nodes/DexNode.java index 6f12520e6..90b7c4eaf 100644 --- a/src/main/java/jadx/dex/nodes/DexNode.java +++ b/src/main/java/jadx/dex/nodes/DexNode.java @@ -30,7 +30,7 @@ public class DexNode { private final List classes = new ArrayList(); private final String[] strings; - public DexNode(RootNode root, InputFile input) throws IOException, DecodeException { + public DexNode(RootNode root, InputFile input) { this.root = root; this.dexBuf = input.getDexBuffer(); diff --git a/src/main/java/jadx/dex/nodes/InsnNode.java b/src/main/java/jadx/dex/nodes/InsnNode.java index 5c5e050aa..92456462c 100644 --- a/src/main/java/jadx/dex/nodes/InsnNode.java +++ b/src/main/java/jadx/dex/nodes/InsnNode.java @@ -71,7 +71,7 @@ public class InsnNode extends AttrNode { public boolean containsArg(RegisterArg arg) { for (InsnArg a : arguments) { - if (a == arg || (a.isRegister() && ((RegisterArg) a).getRegNum() == arg.getRegNum())) + if (a == arg || (a.isRegister() && a.getRegNum() == arg.getRegNum())) return true; } return false; diff --git a/src/main/java/jadx/dex/nodes/MethodNode.java b/src/main/java/jadx/dex/nodes/MethodNode.java index 9f287afa2..c27364c80 100644 --- a/src/main/java/jadx/dex/nodes/MethodNode.java +++ b/src/main/java/jadx/dex/nodes/MethodNode.java @@ -100,8 +100,7 @@ public class MethodNode extends AttrNode implements ILoadable { initJumps(insnByOffset); if (mthCode.getDebugInfoOffset() > 0) { - DebugInfoParser debugInfo = new DebugInfoParser(this, mthCode.getDebugInfoOffset()); - debugInfo.process(insnByOffset); + (new DebugInfoParser(this, mthCode.getDebugInfoOffset(), insnByOffset)).process(); } } catch (Exception e) { throw new DecodeException(this, "Load method exception", e); diff --git a/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java b/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java index 1f3077371..5a57c294e 100644 --- a/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java +++ b/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java @@ -30,6 +30,7 @@ public class BlockMakerVisitor extends AbstractVisitor { // leave these instructions alone in block node private static final Set separateInsns = EnumSet.of( + InsnType.RETURN, InsnType.IF, InsnType.SWITCH, InsnType.MONITOR_ENTER, @@ -165,12 +166,8 @@ public class BlockMakerVisitor extends AbstractVisitor { } } } - computeDominators(mth); - - for (BlockNode block : mth.getBasicBlocks()) { - markReturnBlocks(mth, block); - } + markReturnBlocks(mth); int i = 0; while (modifyBlocksTree(mth)) { @@ -178,6 +175,7 @@ public class BlockMakerVisitor extends AbstractVisitor { cleanDomTree(mth); // recalculate dominators tree computeDominators(mth); + markReturnBlocks(mth); i++; if (i > 100) @@ -273,7 +271,7 @@ public class BlockMakerVisitor extends AbstractVisitor { BlockNode idom = mth.getBasicBlocks().get(id); block.setIDom(idom); idom.getDominatesOn().add(block); - } else if (block != entryBlock) { + } else { throw new JadxRuntimeException("Can't find immediate dominator for block " + block + " in " + bs + " prec:" + block.getPredecessors()); } @@ -284,9 +282,8 @@ public class BlockMakerVisitor extends AbstractVisitor { private static void markLoops(MethodNode mth) { for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode succ : block.getSuccessors()) { - // Every successor that dominates its predecessor - // must be the header of a loop. - // That is, block -> succ is a back edge. + // Every successor that dominates its predecessor is a header of a loop, + // block -> succ is a back edge. if (block.getDoms().get(succ.getId())) { succ.getAttributes().add(AttributeFlag.LOOP_START); block.getAttributes().add(AttributeFlag.LOOP_END); @@ -299,10 +296,12 @@ public class BlockMakerVisitor extends AbstractVisitor { } } - private static void markReturnBlocks(MethodNode mth, BlockNode block) { - if (block.getInstructions().size() == 1) { - if (block.getInstructions().get(0).getType() == InsnType.RETURN) - block.getAttributes().add(AttributeFlag.RETURN); + private static void markReturnBlocks(MethodNode mth) { + for (BlockNode block : mth.getBasicBlocks()) { + if (block.getInstructions().size() == 1) { + if (block.getInstructions().get(0).getType() == InsnType.RETURN) + block.getAttributes().add(AttributeFlag.RETURN); + } } } diff --git a/src/main/java/jadx/dex/visitors/BlockProcessingHelper.java b/src/main/java/jadx/dex/visitors/BlockProcessingHelper.java index e747bd741..3079710bc 100644 --- a/src/main/java/jadx/dex/visitors/BlockProcessingHelper.java +++ b/src/main/java/jadx/dex/visitors/BlockProcessingHelper.java @@ -45,9 +45,10 @@ public class BlockProcessingHelper { // set correct type for 'move-exception' operation RegisterArg excArg = me.getResult(); if (excHandler.isCatchAll()) - excArg.getTypedVar().merge(ArgType.THROWABLE); + excArg.getTypedVar().forceSetType(ArgType.THROWABLE); else - excArg.getTypedVar().merge(excHandler.getCatchType().getType()); + excArg.getTypedVar().forceSetType(excHandler.getCatchType().getType()); + // excArg.getTypedVar().merge(excHandler.getCatchType().getType()); excHandler.setArg(excArg); block.getAttributes().add(handlerAttr); diff --git a/src/main/java/jadx/dex/visitors/ConstInlinerVisitor.java b/src/main/java/jadx/dex/visitors/ConstInlinerVisitor.java index f61006e03..4c87fa212 100644 --- a/src/main/java/jadx/dex/visitors/ConstInlinerVisitor.java +++ b/src/main/java/jadx/dex/visitors/ConstInlinerVisitor.java @@ -34,7 +34,7 @@ public class ConstInlinerVisitor extends AbstractVisitor { } } - public static boolean checkInsn(MethodNode mth, BlockNode block, InsnNode insn) { + private static boolean checkInsn(MethodNode mth, BlockNode block, InsnNode insn) { if (insn.getType() == InsnType.CONST) { if (insn.getArgsCount() == 1 && insn.getArg(0).isLiteral() diff --git a/src/main/java/jadx/dex/visitors/DotGraphVisitor.java b/src/main/java/jadx/dex/visitors/DotGraphVisitor.java index ac41ecedb..8dccbbba7 100644 --- a/src/main/java/jadx/dex/visitors/DotGraphVisitor.java +++ b/src/main/java/jadx/dex/visitors/DotGraphVisitor.java @@ -75,7 +75,7 @@ public class DotGraphVisitor extends AbstractVisitor { dot.add(conn); - dot.startLine("}"); + dot.startLine('}'); dot.startLine(); String fileName = Utils.escape(mth.getMethodInfo().getShortId()) @@ -99,7 +99,7 @@ public class DotGraphVisitor extends AbstractVisitor { processRegion(mth, c, dot, conn); } - dot.startLine("}"); + dot.startLine('}'); } else if (region instanceof BlockNode) { processBlock(mth, (BlockNode) region, dot, conn); } diff --git a/src/main/java/jadx/dex/visitors/MethodInlinerVisitor.java b/src/main/java/jadx/dex/visitors/MethodInlinerVisitor.java index c9b7e90a5..dd8418a7d 100644 --- a/src/main/java/jadx/dex/visitors/MethodInlinerVisitor.java +++ b/src/main/java/jadx/dex/visitors/MethodInlinerVisitor.java @@ -40,8 +40,7 @@ public class MethodInlinerVisitor extends AbstractVisitor { if (block.getInstructions().size() == 1) { InsnNode insn = block.getInstructions().get(0); addInlineAttr(mth, insn); - return; - } + } } } } diff --git a/src/main/java/jadx/utils/BlockUtils.java b/src/main/java/jadx/utils/BlockUtils.java index acad20f25..16dafc10d 100644 --- a/src/main/java/jadx/utils/BlockUtils.java +++ b/src/main/java/jadx/utils/BlockUtils.java @@ -39,7 +39,7 @@ public class BlockUtils { return list.get(1); } - public static List cleanBlockList(List list) { + private static List cleanBlockList(List list) { List ret = new ArrayList(list.size()); for (BlockNode block : list) { if (!block.getAttributes().contains(AttributeType.EXC_HANDLER)) @@ -52,11 +52,8 @@ public class BlockUtils { if (from.getCleanSuccessors().contains(to)) return false; // already checked - if (!from.getSuccessors().contains(to)) - return false; // not even successor - - return true; - } + return from.getSuccessors().contains(to); + } /** * Remove exception handlers from block nodes bitset diff --git a/src/main/java/jadx/utils/StringUtils.java b/src/main/java/jadx/utils/StringUtils.java index 1acdf7fe6..b2ad0c103 100644 --- a/src/main/java/jadx/utils/StringUtils.java +++ b/src/main/java/jadx/utils/StringUtils.java @@ -22,7 +22,7 @@ public class StringUtils { return '\'' + res.toString() + '\''; } - public static void processChar(int c, StringBuilder res) { + private static void processChar(int c, StringBuilder res) { switch (c) { case '\n': res.append("\\n"); diff --git a/src/main/java/jadx/utils/Utils.java b/src/main/java/jadx/utils/Utils.java index fb9962829..e568e05a0 100644 --- a/src/main/java/jadx/utils/Utils.java +++ b/src/main/java/jadx/utils/Utils.java @@ -126,7 +126,7 @@ public class Utils { public static String getJadxVersion() { try { Enumeration resources = - new Utils().getClass().getClassLoader().getResources("META-INF/MANIFEST.MF"); + Utils.class.getClassLoader().getResources("META-INF/MANIFEST.MF"); while (resources.hasMoreElements()) { Manifest manifest = new Manifest(resources.nextElement().openStream()); String ver = manifest.getMainAttributes().getValue("jadx-version");