/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * NullingBytecodeRewriter.java * Created: October 15, 2007 * By: Malcolm Sharpe */ package org.openquark.cal.internal.javamodel; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; /** * A command-line tool for rewriting Java bytecode to reduce memory usage * in certain cases. Supports rewriting individual class files and JARs. * See NullingClassAdapter for internal details. * * @author Malcolm Sharpe */ public final class NullingBytecodeRewriter { /** * Run the NullingBytecodeRewriter from the command line. * This supports rewriting single class files or entire JAR * files. * * @param args */ public static void main(String[] args) throws Exception { if (args.length != 2) usage(); if (args[0].endsWith(".class")) { rewriteClass(args[0], args[1]); } else if (args[0].endsWith(".jar")) { rewriteJar(args[0], args[1]); } else { usage(); } } /** * Print usage information for running NullingBytecodeRewriter from * the command line. */ private static void usage() { System.err.println("Usage: java org.openquark.cal.internal.javamodel.NullingBytecodeRewriter in_path out_path"); System.err.println(" where"); System.err.println(" in_path and out_path are paths to either class files or JAR files"); System.exit(1); } /** * Rewrite a JAR file. * * @param inputPath the path to the input JAR file. * @param outputPath the path to which to write the rewritten JAR file. * @throws IOException if there was an error reading or writing the JAR files. */ public static void rewriteJar(String inputPath, String outputPath) throws IOException { ZipFile zf = new ZipFile(inputPath); Enumeration<? extends ZipEntry> e = zf.entries(); ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outputPath)); while (e.hasMoreElements()) { ZipEntry entry = e.nextElement(); ZipEntry newEntry = new ZipEntry(entry); InputStream is = zf.getInputStream(entry); if (entry.getName().endsWith(".class")) { byte[] rewritten = rewriteClass(is); newEntry.setSize(rewritten.length); newEntry.setCompressedSize(-1); zos.putNextEntry(newEntry); zos.write(rewritten); } else { newEntry.setCompressedSize(-1); zos.putNextEntry(newEntry); int b; while (-1 != (b = is.read())) { zos.write(b); } is.close(); } } zos.close(); } /** * Rewrite a class file. * * @param inputPath the path to the input class file. * @param outputPath the path to which to write the rewritten class file. * @throws IOException if there was an error reading or writing the class files. */ public static void rewriteClass(String inputPath, String outputPath) throws IOException { byte[] result = rewriteClass(new FileInputStream(inputPath)); FileOutputStream out = new FileOutputStream(outputPath); out.write(result); out.close(); } /** * Rewrite a class read from the given input stream and return the rewritten bytes. * * @param source a stream containing the input class. * @return the rewritten class bytecode. * @throws IOException if there was an error reading the class from the input stream. */ public static byte[] rewriteClass(InputStream source) throws IOException { ClassReader cr = new ClassReader(source); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS/* | ClassWriter.COMPUTE_FRAMES*/); ClassAdapter ca = new NullingClassAdapter(cw); cr.accept(ca, 0); return cw.toByteArray(); } }