/** * Chain together a ClassReader than will read the given class and a ClassWriter to write out a * new class with an adapter in the middle to add annotations * * @param fromName the name of the class we're coming from */ private static void adaptClass(String fromName) { if (VERBOSE) System.out.println("Adding annotations to class: " + fromName); // gets an input stream to read the bytecode of the class String resource = fromName.replace('.', '/') + ".class"; InputStream is = BootstrapClassLoader.getBootstrapClassLoader().getResourceAsStream(resource); byte[] b; // adapts the class on the fly try { ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(0); ClassVisitor cv = new AddAnnotationClassAdapter(cw, fromName); cr.accept(cv, 0); b = cw.toByteArray(); } catch (Exception e) { throw new Error("Couldn't find class " + fromName + " (" + resource + ")", e); } // store the adapted class on disk try { File file = new File(destinationDir + resource); new File(file.getParent()).mkdirs(); // ensure we have a directory to write to FileOutputStream fos = new FileOutputStream(file); fos.write(b); fos.close(); } catch (Exception e) { throw new Error("Error writing to " + destinationDir + resource + " to disk", e); } }
private String getFieldType(String owner, String name) { if (fieldDescriptions.containsKey(owner)) { return fieldDescriptions.get(owner).get(name); } synchronized (fieldDescriptions) { try { byte[] classBytes = ClassPatchManager.INSTANCE.getPatchedResource( owner, map(owner).replace('/', '.'), classLoader); if (classBytes == null) { return null; } ClassReader cr = new ClassReader(classBytes); ClassNode classNode = new ClassNode(); cr.accept( classNode, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); Map<String, String> resMap = Maps.newHashMap(); for (FieldNode fieldNode : (List<FieldNode>) classNode.fields) { resMap.put(fieldNode.name, fieldNode.desc); } fieldDescriptions.put(owner, resMap); return resMap.get(name); } catch (IOException e) { FMLRelaunchLog.log( Level.ERROR, e, "A critical exception occured reading a class file %s", owner); } return null; } }
public static void main(String[] args) throws IOException { InputStream in = App.class.getResourceAsStream("App.class"); ClassPrinter cp = new ClassPrinter(); ClassReader cr = new ClassReader(in); cr.accept(cp, 0); in.close(); }
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { try { ClassReader classReader = new ClassReader("com/asm/Before_Demo1"); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassAdapter ca = new AopClassAdapter(cw); classReader.accept(ca, ClassReader.SKIP_DEBUG); byte[] byteArray = cw.toByteArray(); MyClassLoader myClassLoader = new MyClassLoader(); Class<?> clazz = myClassLoader.myDefineClass(byteArray, "com.asm.Before_Demo1"); Method method = clazz.getMethod("sayHello"); method.invoke(clazz.newInstance()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
@Override public byte[] transform(String name, String transformedName, byte[] bytes) { if (transformedName.equals("net.minecraft.block.BlockDynamicLiquid") && CoreLoadingPlugin.util.getBoolean("FiniteWater", false)) { ClassReader reader = new ClassReader(bytes); ClassNode node = new ClassNode(); reader.accept(node, 0); InsnList getSmallestFlowDecay = new InsnList(); getSmallestFlowDecay.add(new VarInsnNode(ALOAD, 0)); getSmallestFlowDecay.add(new InsnNode(ICONST_0)); getSmallestFlowDecay.add( new FieldInsnNode( PUTFIELD, "net/minecraft/block/BlockDynamicLiquid", "field_149815_a", "I")); for (MethodNode method : node.methods) if ("func_149810_a" .equals( FMLDeobfuscatingRemapper.INSTANCE.mapMethodName(name, method.name, method.desc))) method.instructions.insertBefore(method.instructions.getFirst(), getSmallestFlowDecay); ClassWriter writer = new ClassWriter(0); node.accept(writer); return writer.toByteArray(); } return bytes; }
public synchronized Map<String, String> getImportedClasses(String name) throws ClassNotFoundException { if (dontBother.contains(name)) { throw new ClassNotFoundException(name); } try { ClassReader reader = new ClassReader(getResourceAsStream(name.replace('.', '/') + ".class")); PMDASMVisitor asmVisitor = new PMDASMVisitor(); reader.accept(asmVisitor, 0); List<String> inner = asmVisitor.getInnerClasses(); if (inner != null && !inner.isEmpty()) { inner = new ArrayList<String>(inner); // to avoid ConcurrentModificationException for (String str : inner) { reader = new ClassReader(getResourceAsStream(str.replace('.', '/') + ".class")); reader.accept(asmVisitor, 0); } } return asmVisitor.getPackages(); } catch (IOException e) { dontBother.add(name); throw new ClassNotFoundException(name, e); } }
@Override public boolean apply(MethodRef input) { String owner = input.getOwner(); if (owner.charAt(0) == '[') { owner = "java/lang/Object"; } Map<Key, Boolean> map = this.map.get(owner); if (map == null) { try (InputStream in = loader.getResourceAsStream(owner + ".class")) { if (in == null) { throw new IllegalArgumentException("Object type " + owner + " not found"); } ClassReader reader = new ClassReader(in); map = new HashMap<>(); ClassAdapter adapter = new ClassAdapter(map); reader.accept(adapter, SKIP_DEBUG | SKIP_FRAMES); } catch (IOException e) { throw new IllegalArgumentException(e); } Map<Key, Boolean> prevMap = this.map.putIfAbsent(owner, map); if (prevMap != null) { map = prevMap; } } String name = input.getName(); String desc = input.getDesc(); Boolean suspendable = map.get(new Key(name, desc)); if (suspendable == null) { throw new IllegalArgumentException("Method " + owner + '.' + name + desc + " not found"); } return suspendable; }
protected Set<Class> processFileUrl(URL url, String basepath, Class clazz) throws IOException { Set<Class> set = new HashSet<Class>(); String urlBase = url.getFile(); // We can't URLDecoder.decode(path) since some encoded chars are allowed on file uris urlBase = urlBase.replaceAll("%20", " "); File dir = new File(urlBase); if (!dir.isDirectory()) { logger.warn("Cannot process File URL: " + url + ". Path is not a directory"); return set; } Collection<File> files = FileUtils.listFiles(new File(urlBase), new String[] {"class"}, true); for (File file : files) { try { InputStream classStream = new FileInputStream(file); ClassReader reader = new ClosableClassReader(classStream); ClassScanner visitor = getScanner(clazz); reader.accept(visitor, 0); if (visitor.isMatch()) { Class c = loadClass(visitor.getClassName()); if (c != null) { set.add(c); } } } catch (IOException e) { if (logger.isDebugEnabled()) { Throwable t = ExceptionHelper.getRootException(e); logger.debug(String.format("%s: caused by: %s", e.toString(), t.toString())); } } } return set; }
private static void transformIfNeccessary(File file) throws IOException { InputStream is = new FileInputStream(file); ClassNode cn; try { ClassReader cr = new ClassReader(is); cn = new ClassNode(); cr.accept(cn, 0); } finally { is.close(); } if (!isAlreadyTransformed(cn) && isAnnotationPresent(cn)) { System.out.println("Transforming file " + file); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor ca = new CheckClassAdapter(cw); ClassVisitor cv = new PropertyChangeSupportAdapter(ca); cn.accept(cv); FileOutputStream os = new FileOutputStream(file); try { os.write(cw.toByteArray()); } finally { os.close(); } } }
/** * Determine imports for a class given as a String resource. This method doesn't do any search for * the enclosing/inner classes as it considers that these should be handled at a higher level. * * <p>The returned set contains the packages in string format (i.e. java.io) * * @param className * @param resource * @return */ private Set determineImportsForClass(String className, Resource resource) { Assert.notNull(resource, "a not-null class is required"); DependencyVisitor visitor = new DependencyVisitor(); boolean trace = logger.isTraceEnabled(); ClassReader reader; try { if (trace) logger.trace("Visiting class " + className); reader = new ClassReader(resource.getInputStream()); } catch (Exception ex) { throw (RuntimeException) new IllegalArgumentException("Cannot read class " + className).initCause(ex); } reader.accept(visitor, false); // convert from / to . format Set originalPackages = visitor.getPackages(); Set pkgs = new LinkedHashSet(originalPackages.size()); for (Iterator iterator = originalPackages.iterator(); iterator.hasNext(); ) { String pkg = (String) iterator.next(); pkgs.add(pkg.replace('/', '.')); } return pkgs; }
protected Set<Class> processJarUrl(URL url, String basepath, Class clazz) throws IOException { Set<Class> set = new HashSet<Class>(); String path = url.getFile().substring(5, url.getFile().indexOf("!")); JarFile jar = new JarFile(path); for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) { JarEntry entry = (JarEntry) entries.nextElement(); if (entry.getName().startsWith(basepath) && entry.getName().endsWith(".class")) { try { String name = entry.getName(); // Ignore anonymous // TODO RM what about the other anonymous classes like $2, $3 ? if (name.contains("$1")) { continue; } URL classURL = classLoader.getResource(name); ClassReader reader = new ClassReader(classURL.openStream()); ClassScanner visitor = getScanner(clazz); reader.accept(visitor, 0); if (visitor.isMatch()) { Class c = loadClass(visitor.getClassName()); if (c != null) { set.add(c); } } } catch (Exception e) { if (logger.isDebugEnabled()) { Throwable t = ExceptionHelper.getRootException(e); logger.debug(String.format("%s: caused by: %s", e.toString(), t.toString())); } } } } return set; }
public static void dumpClass(String className, byte[] data) { System.out.println("DUMP OF CLASS: " + className); ClassReader cr = new ClassReader(data); ClassVisitor cv = new TraceClassVisitor(null, new Textifier(), new PrintWriter(System.out)); cr.accept(cv, ClassReader.SKIP_FRAMES); System.out.println("================="); }
@Test public void testMethodClass() throws IOException { ClassReader reader = new ClassReader("TestFiles.TestJavaCodeASMParsing"); ClassVisitor visitor = new ClassDecorationVisitor(Opcodes.ASM5); ClassVisitor fieldVisitor = new ClassFieldVisitor(Opcodes.ASM5, visitor); ClassVisitor methodVisitor = new ClassMethodVisitor(Opcodes.ASM5, fieldVisitor); reader.accept(methodVisitor, ClassReader.EXPAND_FRAMES); Map<String, MethodClass> methods = new HashMap<String, MethodClass>(); methods = ((ClassMethodVisitor) methodVisitor).getMethodsInfoCollection(); ArrayList<String> methodsName = new ArrayList<String>(); methodsName.add("add"); methodsName.add("println"); methodsName.add("getA"); methodsName.add("getB"); methodsName.add("getC"); methodsName.add("print"); assertEquals(methodsName.size(), methods.keySet().size() - 1); for (String k : methods.keySet()) { if (!methods.get(k).getName().contains("init")) { assertTrue(methodsName.contains(methods.get(k).getName())); methodsName.remove(methods.get(k).getName()); } } }
@Override public void parse( final BytecodeArtifact bytecodeArtifact, final IPathResolver directoryResolver) { assert null != bytecodeArtifact : "Parameter 'bytecodeArtifact' of method 'parse' must not be null"; /** (1) */ final ClassReader cr = new ClassReader(bytecodeArtifact.getBytesOriginal()); /** (2) */ // cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); final ClassWriter cw = new ClassWriter(cr, 0); /** (3) */ final ASMClassInstrumentor ca = constructSelf(cw); /** (4) */ cr.accept(ca, ClassReader.EXPAND_FRAMES); assert null != ca : "'ca' of method 'parse' must not be null"; assert null != cw : "'cw' of method 'parse' must not be null"; final String fileAbsolutePath = bytecodeArtifact.absolutePath(); this.benchmark.addBytecodeArtificatAnalysed( ca.className, cw.toByteArray(), fileAbsolutePath, directoryResolver, bytecodeArtifact.isClassFile(), this.isInterface); }
private boolean readClass(String clazz) throws IOException { ClassReader cr = new ClassReader(new FileInputStream(clazz)); ClassNode ca = new ClassNode() { public void visitEnd() { // accept(cv); } }; cr.accept(new CheckClassAdapter(ca), true); boolean failed = false; List methods = ca.methods; for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); if (method.instructions.size() > 0) { Analyzer a = new Analyzer(new SimpleVerifier()); try { a.analyze(ca.name, method); continue; } catch (Exception e) { e.printStackTrace(); } final Frame[] frames = a.getFrames(); if (!failed) { failed = true; log("verifying of class " + clazz + " failed"); } if (verbose) log(method.name + method.desc); TraceMethodVisitor cv = new TraceMethodVisitor(null) { public void visitMaxs(int maxStack, int maxLocals) { StringBuffer buffer = new StringBuffer(); for (int i = 0; i < text.size(); ++i) { String s = frames[i] == null ? "null" : frames[i].toString(); while (s.length() < maxStack + maxLocals + 1) { s += " "; } buffer.append(Integer.toString(i + 100000).substring(1)); buffer.append(" "); buffer.append(s); buffer.append(" : "); buffer.append(text.get(i)); } if (verbose) log(buffer.toString()); } }; for (int j = 0; j < method.instructions.size(); ++j) { Object insn = method.instructions.get(j); if (insn instanceof AbstractInsnNode) { ((AbstractInsnNode) insn).accept(cv); } else { cv.visitLabel((Label) insn); } } cv.visitMaxs(method.maxStack, method.maxLocals); } } return !failed; }
/** * For debugging, it's useful to dump the content of the generated classes along with the * exception that was generated. * * <p>However to make it work you need to pull in the org.objectweb.asm.util.TraceClassVisitor * class and associated utilities which are found in the ASM source jar. Since we don't want that * dependency in the source code, we only put it manually for development and access the * TraceClassVisitor via reflection if present. * * @param t The exception thrown by {@link ClassLoader2#testModifiedInstance()} * @param cl2 The {@link ClassLoader2} instance with the generated bytecode. * @return Either original {@code t} or a new wrapper {@link Throwable} */ private Throwable dumpGeneratedClass(Throwable t, ClassLoader2 cl2) { try { // For debugging, dump the bytecode of the class in case of unexpected error // if we can find the TraceClassVisitor class. Class<?> tcvClass = Class.forName("org.objectweb.asm.util.TraceClassVisitor"); StringBuilder sb = new StringBuilder(); sb.append('\n').append(t.getClass().getCanonicalName()); if (t.getMessage() != null) { sb.append(": ").append(t.getMessage()); } for (Entry<String, byte[]> entry : cl2.getByteCode()) { String className = entry.getKey(); byte[] bytes = entry.getValue(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); // next 2 lines do: TraceClassVisitor tcv = new TraceClassVisitor(pw); Constructor<?> cons = tcvClass.getConstructor(new Class<?>[] {pw.getClass()}); Object tcv = cons.newInstance(new Object[] {pw}); ClassReader cr2 = new ClassReader(bytes); cr2.accept((ClassVisitor) tcv, 0 /* flags */); sb.append("\nBytecode dump: <").append(className).append(">:\n").append(sw.toString()); } // Re-throw exception with new message RuntimeException ex = new RuntimeException(sb.toString(), t); return ex; } catch (Throwable ignore) { // In case of problem, just throw the original exception as-is. return t; } }
public static void main(final String[] args) throws FileNotFoundException, IOException { String classFileName = ""; try { classFileName = args[0]; } catch (Exception exp) { die("check class file name (first argument)"); } String methodNameAndDescriptor = ""; try { methodNameAndDescriptor = args[1]; } catch (Exception exp) { die("check method name and descriptor (second argument)"); } final ClassReader cr = new ClassReader(new FileInputStream(classFileName)); final ClassNode cnode = new ClassNode(); cr.accept(cnode, 0); ControlFlowGraphExtractor control = new ControlFlowGraphExtractor(); control.flow(cnode, methodNameAndDescriptor); System.out.println("\n# READY."); }
protected Set<Class> processFileUrl(URL url, String basepath, Class clazz) throws IOException { Set<Class> set = new HashSet<Class>(); String urlBase = url.getFile(); urlBase = URLDecoder.decode(urlBase); Collection<File> files = FileUtils.listFiles(new File(urlBase), new String[] {"class"}, true); for (File file : files) { try { ClassReader reader = new ClassReader(new FileInputStream(file)); ClassScanner visitor = getScanner(clazz); reader.accept(visitor, 0); if (visitor.isMatch()) { Class c = loadClass(visitor.getClassName()); if (c != null) { set.add(c); } } } catch (IOException e) { if (logger.isDebugEnabled()) { Throwable t = ExceptionHelper.getRootException(e); logger.debug(String.format("%s: caused by: %s", e.toString(), t.toString())); } } } return set; }
/** {@inheritDoc} */ public void readClass(InputStream in, VisitorAdapter<ClassVisitorImpl> visitor) throws IOException { ClassReader reader = new ClassReader(in); reader.accept( (ClassVisitor) visitor, ClassReader.SKIP_CODE & ClassReader.SKIP_DEBUG & ClassReader.SKIP_FRAMES); }
@Override public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { if (superName != null) { this.nameOfSuper = superName.replaceAll("/", "."); try { reader = new ClassReader(superName); ClassVisitor visitor = new MethodGetterVisitor(Opcodes.ASM5, superMethods); reader.accept(visitor, ClassReader.EXPAND_FRAMES); } catch (IOException e) { } } if (null != interfaces && interfaces.length == 1) { this.interfaces = interfaces; try { reader = new ClassReader(interfaces[0]); ClassVisitor visitor = new MethodGetterVisitor(Opcodes.ASM5, interfaceMethods); reader.accept(visitor, ClassReader.EXPAND_FRAMES); } catch (IOException e) { } } super.visit(version, access, name, signature, superName, interfaces); }
public String submitClassFile(byte[] data) { ClassNode node = new ClassNode(); org.objectweb.asm.ClassReader reader = new org.objectweb.asm.ClassReader(data); reader.accept(node, 0); submitClass(new Parser(new ReferenceCache()).parseClass(node)); return node.name; }
private void processEntry( final ZipInputStream zis, final ZipEntry ze, final ContentHandlerFactory handlerFactory) { ContentHandler handler = handlerFactory.createContentHandler(); try { // if (CODE2ASM.equals(command)) { // read bytecode and process it // // with TraceClassVisitor // ClassReader cr = new ClassReader(readEntry(zis, ze)); // cr.accept(new TraceClassVisitor(null, new PrintWriter(os)), // false); // } boolean singleInputDocument = inRepresentation == SINGLE_XML; if (inRepresentation == BYTECODE) { // read bytecode and process it // with handler ClassReader cr = new ClassReader(readEntry(zis, ze)); cr.accept(new SAXClassAdapter(handler, singleInputDocument), 0); } else { // read XML and process it with handler XMLReader reader = XMLReaderFactory.createXMLReader(); reader.setContentHandler(handler); reader.parse( new InputSource( singleInputDocument ? (InputStream) new ProtectedInputStream(zis) : new ByteArrayInputStream(readEntry(zis, ze)))); } } catch (Exception ex) { update(ze.getName(), 0); update(ex, 0); } }
@SuppressWarnings("unused") @Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { return super.findClass(name); } catch (ClassNotFoundException e) { byte[] def = mClassDefs.get(name); if (def != null) { // Load the modified ClassWithNative from its bytes representation. return defineClass(name, def, 0, def.length); } try { // Load everything else from the original definition into the new class loader. ClassReader cr = new ClassReader(name); ClassWriter cw = new ClassWriter(0); cr.accept(cw, 0); byte[] bytes = cw.toByteArray(); return defineClass(name, bytes, 0, bytes.length); } catch (IOException ioe) { throw new RuntimeException(ioe); } } }
private static Map<String, Class<?>> defineClasses( List<ClassDefinition> classDefinitions, DynamicClassLoader classLoader) { ClassInfoLoader classInfoLoader = ClassInfoLoader.createClassInfoLoader(classDefinitions, classLoader); if (DUMP_BYTE_CODE_TREE) { ByteArrayOutputStream out = new ByteArrayOutputStream(); DumpByteCodeVisitor dumpByteCode = new DumpByteCodeVisitor(new PrintStream(out)); for (ClassDefinition classDefinition : classDefinitions) { dumpByteCode.visitClass(classDefinition); } System.out.println(new String(out.toByteArray(), StandardCharsets.UTF_8)); } Map<String, byte[]> byteCodes = new LinkedHashMap<>(); for (ClassDefinition classDefinition : classDefinitions) { ClassWriter cw = new SmartClassWriter(classInfoLoader); classDefinition.visit(cw); byte[] byteCode = cw.toByteArray(); if (RUN_ASM_VERIFIER) { ClassReader reader = new ClassReader(byteCode); CheckClassAdapter.verify(reader, classLoader, true, new PrintWriter(System.out)); } byteCodes.put(classDefinition.getType().getJavaClassName(), byteCode); } String dumpClassPath = DUMP_CLASS_FILES_TO.get(); if (dumpClassPath != null) { for (Map.Entry<String, byte[]> entry : byteCodes.entrySet()) { File file = new File( dumpClassPath, ParameterizedType.typeFromJavaClassName(entry.getKey()).getClassName() + ".class"); try { log.debug("ClassFile: " + file.getAbsolutePath()); Files.createParentDirs(file); Files.write(entry.getValue(), file); } catch (IOException e) { log.error(e, "Failed to write generated class file to: %s" + file.getAbsolutePath()); } } } if (DUMP_BYTE_CODE_RAW) { for (byte[] byteCode : byteCodes.values()) { ClassReader classReader = new ClassReader(byteCode); classReader.accept( new TraceClassVisitor(new PrintWriter(System.err)), ClassReader.SKIP_FRAMES); } } Map<String, Class<?>> classes = classLoader.defineClasses(byteCodes); try { for (Class<?> clazz : classes.values()) { Reflection.initialize(clazz); } } catch (VerifyError e) { throw new RuntimeException(e); } return classes; }
private CollectClassData collect(String className) { byte[] bytes = getClassBytes(className); assertNotNull("Couldn't load bytes for " + className, bytes); CollectClassData cv = new CollectClassData(); ClassReader reader = new ClassReader(bytes); reader.accept(cv, 0); return cv; }
private String asmDump(InputStream inputStream) throws IOException { ClassReader reader = new ClassReader(inputStream); StringWriter writer = new StringWriter(); reader.accept(new TraceClassVisitor(new PrintWriter(writer)), 0); String code = writer.toString().trim(); return code; }
@Override public byte[] transform(String className, String transformedClassName, byte[] bytes) { String methodName; if (className.equals(OBF_CLASS)) { methodName = SRG_METHOD; } else if (className.equals(MCP_CLASS)) { methodName = MCP_METHOD; } else { return bytes; } ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); for (MethodNode method : classNode.methods) { if (method.name.equals(methodName) && method.desc.equals(METHOD_DESC)) { logger.info("CraftingTweaks will now patch {} in {}...", methodName, className); MethodNode mn = new MethodNode(); Label notClicked = new Label(); // mn.visitMethodInsn(Opcodes.INVOKESTATIC, "org/lwjgl/input/Mouse", "getEventButtonState", // "()Z", false); // mn.visitJumpInsn(Opcodes.IFEQ, notClicked); // if getEventButtonState false, continue // after mn.visitVarInsn(Opcodes.ILOAD, 1); // push mouseX mn.visitVarInsn(Opcodes.ILOAD, 2); // push mouseY mn.visitVarInsn(Opcodes.ILOAD, 3); // push button mn.visitMethodInsn( Opcodes.INVOKESTATIC, "net/blay09/mods/craftingtweaks/CraftingTweaks", "onGuiClick", "(III)Z", false); // call onGuiClick mn.visitJumpInsn(Opcodes.IFEQ, notClicked); // if onGuiClick false, continue after mn.visitInsn(Opcodes.RETURN); // otherwise stop here mn.visitLabel(notClicked); // continue from here AbstractInsnNode insertAfter = null; for (int i = 0; i < method.instructions.size(); i++) { AbstractInsnNode node = method.instructions.get(i); if (node instanceof VarInsnNode) { if (node.getOpcode() == Opcodes.ISTORE && ((VarInsnNode) node).var == 3) { // ISTORE 3 insertAfter = node; break; } } } if (insertAfter != null) { method.instructions.insert(insertAfter, mn.instructions); logger.info("CraftingTweaks successfully patched {} in {}!", methodName, className); } else { logger.warn( "CraftingTweaks failed to patch {0}::{1} ({2} not found) - transfering into crafting grids will not work!", className, methodName, "ISTORE 3"); } } } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }
public void MERGE(byte[] bytes) { ClassReader cr = new ClassReader(bytes); ClassNode merge = new ClassNode(); cr.accept( merge, ClassReader.EXPAND_FRAMES | ClassReader.SKIP_FRAMES); // compute everything from scratch if (this.currentClass == null) this.currentClass = merge; }
public void run() throws IOException { ClassReader cr = (inputStream == null) ? new ClassConstantsReader(className) : new ClassConstantsReader(inputStream); ClassVisitor cv = new NameAndSuperClassExtractor(); cr.accept(cv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); }
@Override public byte[] transform(String name, String transformedName, byte[] basicClass) { if (!"net.minecraft.item.ItemStack".equals(name)) return basicClass; ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(basicClass); classReader.accept(classNode, 0); FieldNode itemField = null; for (FieldNode f : classNode.fields) { if (ITEM_TYPE.equals(f.desc) && itemField == null) { itemField = f; } else if (ITEM_TYPE.equals(f.desc)) { throw new RuntimeException("Error processing ItemStack - found a duplicate Item field"); } } if (itemField == null) { throw new RuntimeException( "Error processing ItemStack - no Item field declared (is the code somehow obfuscated?)"); } MethodNode getItemMethod = null; for (MethodNode m : classNode.methods) { if (GETITEM_DESC.equals(m.desc) && getItemMethod == null) { getItemMethod = m; } else if (GETITEM_DESC.equals(m.desc)) { throw new RuntimeException("Error processing ItemStack - duplicate getItem method found"); } } if (getItemMethod == null) { throw new RuntimeException( "Error processing ItemStack - no getItem method found (is the code somehow obfuscated?)"); } for (MethodNode m : classNode.methods) { for (ListIterator<AbstractInsnNode> it = m.instructions.iterator(); it.hasNext(); ) { AbstractInsnNode insnNode = it.next(); if (insnNode.getType() == AbstractInsnNode.FIELD_INSN) { FieldInsnNode fi = (FieldInsnNode) insnNode; if (itemField.name.equals(fi.name) && fi.getOpcode() == Opcodes.GETFIELD) { it.remove(); MethodInsnNode replace = new MethodInsnNode( Opcodes.INVOKEVIRTUAL, "net/minecraft/item/ItemStack", getItemMethod.name, getItemMethod.desc, false); it.add(replace); } } } } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }