/* * Copyright (c) 2010, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.pack.verify; import java.io.*; import java.util.*; import java.util.jar.*; class JarFileCompare { /* * @author ksrini */ private static VerifyTreeSet getVerifyTreeSet(String jarPath) { VerifyTreeSet vts = new VerifyTreeSet(); try { JarFile j = new JarFile(jarPath); for (JarEntry je : Collections.list((Enumeration<JarEntry>) j.entries())) { if (!je.isDirectory()) { // totally ignore directories vts.add(je.getName()); } } } catch (IOException ioe) { throw new RuntimeException(ioe); } return vts; } private static LinkedList getListOfClasses(String jarPath) { LinkedList l = new LinkedList(); try { JarFile j = new JarFile(jarPath); for (JarEntry je : Collections.list((Enumeration<JarEntry>) j.entries())) { if (!je.isDirectory() && je.getName().endsWith(".class")) { l.add(je.getName()); } } } catch (IOException ioe) { throw new RuntimeException(ioe); } return l; } private static void jarDirectoryCompare(String jarPath1, String jarPath2) { VerifyTreeSet vts1 = getVerifyTreeSet(jarPath1); VerifyTreeSet vts2 = getVerifyTreeSet(jarPath2); TreeSet diff1 = vts1.diff(vts2); if (diff1.size() > 0) { Globals.log("Left has the following entries that right does not have"); Globals.log(diff1.toString()); } TreeSet diff2 = vts2.diff(vts1); if (diff2.size() > 0) { Globals.log("Right has the following entries that left does not have"); Globals.log(diff2.toString()); } if (Globals.checkJarClassOrdering()) { boolean error = false; Globals.println("Checking Class Ordering"); LinkedList l1 = getListOfClasses(jarPath1); LinkedList l2 = getListOfClasses(jarPath2); if (l1.size() != l2.size()) { error = true; Globals.log("The number of classes differs"); Globals.log("\t" + l1.size() + "<>" + l2.size()); } for (int i = 0; i < l1.size(); i++) { String s1 = (String) l1.get(i); String s2 = (String) l2.get(i); if (s1.compareTo(s2) != 0) { error = true; Globals.log("Ordering differs at[" + i + "] = " + s1); Globals.log("\t" + s2); } } } } /* * Returns true if the two Streams are bit identical, and false if they * are not, no further diagnostics */ static boolean compareStreams(InputStream is1, InputStream is2) { BufferedInputStream bis1 = new BufferedInputStream(is1, 8192); BufferedInputStream bis2 = new BufferedInputStream(is2, 8192); try { int i1, i2; int count = 0; while ((i1 = bis1.read()) == (i2 = bis2.read())) { count++; if (i1 < 0) { // System.out.println("bytes read " + count); return true; // got all the way to EOF } } return false; // reads returned dif } catch (IOException ioe) { throw new RuntimeException(ioe); } } private static void checkEntry(JarFile jf1, JarFile jf2, JarEntry je) throws IOException { InputStream is1 = jf1.getInputStream(je); InputStream is2 = jf2.getInputStream(je); if (is1 != null && is2 != null) { if (!compareStreams(jf1.getInputStream(je), jf2.getInputStream(je))) { Globals.println("+++" + je.getName() + "+++"); Globals.log("Error: File:" + je.getName() + " differs, use a diff util for further diagnostics"); } } else { Globals.println("+++" + je.getName() + "+++"); Globals.log("Error: File:" + je.getName() + " not found in " + jf2.getName()); } } /* * Given two jar files we compare and see if the jarfiles have all the * entries. The property ignoreJarDirectories is set to true by default * which means that Directory entries in a jar may be ignore. */ static void jarCompare(String jarPath1, String jarPath2) { jarDirectoryCompare(jarPath1, jarPath2); try { JarFile jf1 = new JarFile(jarPath1); JarFile jf2 = new JarFile(jarPath2); int nclasses = 0; int nentries = 0; int entries_checked = 0; int classes_checked = 0; for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf1.entries())) { if (!je.isDirectory() && !je.getName().endsWith(".class")) { nentries++; } else if (je.getName().endsWith(".class")) { nclasses++; } } for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf1.entries())) { if (je.isDirectory()) { continue; // Ignore directories } if (!je.getName().endsWith(".class")) { entries_checked++; if (je.getName().compareTo("META-INF/MANIFEST.MF") == 0) { Manifest mf1 = new Manifest(jf1.getInputStream(je)); Manifest mf2 = new Manifest(jf2.getInputStream(je)); if (!mf1.equals(mf2)) { Globals.log("Error: Manifests differ"); Globals.log("Manifest1"); Globals.log(mf1.getMainAttributes().entrySet().toString()); Globals.log("Manifest2"); Globals.log(mf2.getMainAttributes().entrySet().toString()); } } else { checkEntry(jf1, jf2, je); } } else if (Globals.bitWiseClassCompare() == true) { checkEntry(jf1, jf2, je); classes_checked++; } } if (Globals.bitWiseClassCompare()) { Globals.println("Class entries checked (byte wise)/Total Class entries = " + classes_checked + "/" + nclasses); } Globals.println("Non-class entries checked/Total non-class entries = " + entries_checked + "/" + nentries); } catch (IOException ioe) { throw new RuntimeException(ioe); } } }