blob: 419fda1ba237fde833e1a475fcf3084e72cc254c [file] [log] [blame]
/*
* 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);
}
}
}