org.f3.tools.bytecodeverifier.Verifier.java Source code

Java tutorial

Introduction

Here is the source code for org.f3.tools.bytecodeverifier.Verifier.java

Source

/*
 * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package org.f3.tools.bytecodeverifier;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.tree.analysis.*;
import org.objectweb.asm.util.CheckClassAdapter;

/**
 * This class verifies bytecode in .class files, .jar files and
 * in directories (recursively) using Objectweb's ASM library.
 *
 * This is intendend to be used to verify class files generated by 
 * f3c and the mangler tool.
 *
 * @author A. Sundararajan
 */
public class Verifier {
    // do not create me!
    private Verifier() {
    }

    private static boolean verify(String name, ClassReader reader, final PrintWriter err, boolean verbose) {
        if (verbose) {
            err.println("Verifying " + name);
        }
        ClassNode classNode = new ClassNode();
        reader.accept(new CheckClassAdapter(classNode), ClassReader.SKIP_DEBUG);

        Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
        List<Type> interfaces = new ArrayList<Type>();
        for (Object iface : classNode.interfaces) {
            interfaces.add(Type.getObjectType(iface.toString()));
        }

        List<MethodNode> methods = classNode.methods;
        for (int i = 0; i < methods.size(); i++) {
            MethodNode method = methods.get(i);
            SimpleVerifier verifier = new SimpleVerifier(Type.getObjectType(classNode.name), syperType, interfaces,
                    false) {

                @Override
                protected boolean isAssignableFrom(Type t, Type u) {
                    // FIXME: Assignment check in the superclass implementation uses
                    // Class.forName to check currently loaded classes. We don't want 
                    // to use loaded Class objects in the test. We leave the reference 
                    // assignment compatibility checks for now.
                    return true;
                }
            };

            Analyzer analyzer = new Analyzer(verifier);
            try {
                analyzer.analyze(classNode.name, method);
            } catch (AnalyzerException exp) {
                err.println("Verification failed for " + name);
                exp.printStackTrace(err);
                err.flush();
                return false;
            }
        }
        err.flush();
        return true;
    }

    private static boolean verifyClass(String name, InputStream is, PrintWriter err, boolean verbose)
            throws IOException {
        ClassReader cr = new ClassReader(is);
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
        ClassVisitor cv = new CheckClassAdapter(cw);
        cr.accept(cv, 0);
        return verify(name, new ClassReader(cw.toByteArray()), err, verbose);
    }

    private static boolean verifyZip(String name, ZipInputStream zis, PrintWriter err, boolean verbose)
            throws IOException {
        if (verbose) {
            err.println("Verifying " + name);
        }
        boolean result = false;
        ZipEntry ze = zis.getNextEntry();
        while (ze != null) {
            if (!ze.isDirectory()) {
                String zname = ze.getName();
                if (zname.endsWith(".class")) {
                    result |= verifyClass(ze.getName(), zis, err, verbose);
                }
            }
            zis.closeEntry();
            ze = zis.getNextEntry();
        }
        return result;
    }

    public static boolean verifyFile(File f, PrintWriter err, boolean verbose) throws IOException {
        if (!f.exists()) {
            err.println(f.getAbsolutePath() + " does not exist!");
        }
        boolean result = false;
        if (f.isDirectory()) {
            File[] contents = f.listFiles();
            for (File c : contents) {
                result |= verifyFile(c, err, verbose);
            }
        } else {
            String path = f.getAbsolutePath();
            InputStream is = new BufferedInputStream(new FileInputStream(f));
            if (path.endsWith(".jar") || path.endsWith(".zip")) {
                ZipInputStream zis = null;
                try {
                    zis = new ZipInputStream(is);
                    result |= verifyZip(path, zis, err, verbose);
                } finally {
                    if (zis != null) {
                        zis.close();
                    }
                    if (is != null) {
                        is.close();
                    }
                }
            } else if (path.endsWith(".class")) {
                // verify single .class
                try {
                    result |= verifyClass(path, is, err, verbose);
                } finally {
                    if (is != null) {
                        is.close();
                    }
                }
            }
        }
        return result;
    }

    public static boolean verifyPath(String path, PrintWriter err, boolean verbose) throws IOException {
        if (verbose) {
            err.println("Verifying " + path);
        }
        boolean result = false;
        String[] files = path.split(File.pathSeparator);
        for (String file : files) {
            result |= verifyFile(new File(file), err, verbose);
        }
        if (verbose && result) {
            err.println("All files in " + path + " verified OK!");
        }
        err.flush();
        return result;
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Usage: java " + Verifier.class + " <path>");
            System.exit(1);
        }
        try {
            verifyPath(args[0], new PrintWriter(System.out), true);
        } catch (IOException exp) {
            exp.printStackTrace();
        }
    }
}