1/* 2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23package sun.tools.pack.verify; 24 25import java.io.*; 26import java.util.*; 27import java.util.jar.*; 28import xmlkit.*; 29 30public class ClassCompare { 31 32 /* 33 * @author ksrini 34 */ 35 private static XMLKit.Element getXMLelement(InputStream is, 36 boolean ignoreUnkAttrs, 37 List<String> ignoreElements) throws IOException { 38 39 ClassReader cr = new ClassReader(); 40 cr.keepOrder = false; 41 XMLKit.Element e = cr.readFrom(is); 42 43 if (ignoreElements != null) { 44 XMLKit.Filter filter = XMLKit.elementFilter(ignoreElements); 45 e.removeAllInTree(filter); 46 } 47 48 if (ignoreUnkAttrs == true) { 49 // This removes any unknown attributes 50 e.removeAllInTree(XMLKit.elementFilter("Attribute")); 51 } 52 return e; 53 } 54 55 private static String getXMLPrettyString(XMLKit.Element e) throws IOException { 56 StringWriter out = new StringWriter(); 57 e.writePrettyTo(out); 58 return out.toString(); 59 } 60 61 private static boolean compareClass0(JarFile jf1, JarFile jf2, 62 JarEntry je, boolean ignoreUnkAttrs, 63 List<String> ignoreElements) 64 throws IOException { 65 66 InputStream is1 = jf1.getInputStream(je); 67 InputStream is2 = jf2.getInputStream(je); 68 69 // First we try to compare the bits if they are the same 70 boolean bCompare = JarFileCompare.compareStreams(is1, is2); 71 72 // If they are the same there is nothing more to do. 73 if (bCompare) { 74 Globals.println("+++" + je.getName() + "+++\t" 75 + "b/b:PASS"); 76 return bCompare; 77 } 78 is1.close(); 79 is2.close(); 80 81 is1 = jf1.getInputStream(je); 82 is2 = jf2.getInputStream(je); 83 84 85 XMLKit.Element e1 = getXMLelement(is1, ignoreUnkAttrs, ignoreElements); 86 XMLKit.Element e2 = getXMLelement(is2, ignoreUnkAttrs, ignoreElements); 87 88 Globals.print("+++" + je.getName() + "+++\t" 89 + e1.size() + "/" + e1.size() + ":"); 90 91 boolean result = true; 92 93 if (e1.equals(e2)) { 94 Globals.println("PASS"); 95 } else { 96 Globals.println("FAIL"); 97 Globals.log("Strings differs"); 98 Globals.log(getXMLPrettyString(e1)); 99 Globals.log("----------"); 100 Globals.log(getXMLPrettyString(e2)); 101 result = false; 102 } 103 return result; 104 } 105 106 /* 107 * Given two Class Paths could be jars the first being a reference 108 * will execute a series of comparisons on the classname specified 109 * The className could be null in which case it will iterate through 110 * all the classes, otherwise it will compare one class and exit. 111 */ 112 public static boolean compareClass(String jar1, String jar2, 113 String className, boolean ignoreUnkAttrs, 114 List<String> ignoreElements) 115 throws IOException { 116 117 Globals.println("Unknown attributes ignored:" + ignoreUnkAttrs); 118 if (ignoreElements != null) { 119 Globals.println(ignoreElements.toString()); 120 } 121 122 JarFile jf1 = new JarFile(jar1); 123 JarFile jf2 = new JarFile(jar2); 124 125 boolean result = true; 126 127 if (className == null) { 128 for (JarEntry je1 : Collections.list((Enumeration<JarEntry>) jf1.entries())) { 129 if (je1.getName().endsWith(".class")) { 130 JarEntry je2 = jf2.getJarEntry(je1.getName()); 131 boolean pf = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements); 132 if (result == true) { 133 result = pf; 134 } 135 } 136 } 137 } else { 138 JarEntry je1 = jf1.getJarEntry(className); 139 result = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements); 140 } 141 if (result == false) { 142 throw new RuntimeException("Class structural comparison failure"); 143 } 144 return result; 145 } 146 147 public static boolean compareClass(String jar1, String jar2, 148 String className) throws IOException { 149 150 Stack<String> s = new Stack(); 151 if (Globals.ignoreDebugAttributes()) { 152 s = new Stack(); 153 s.push("LocalVariable"); 154 s.push("LocalVariableType"); 155 s.push("LineNumber"); 156 s.push("SourceFile"); 157 } 158 return compareClass(jar1, jar2, className, Globals.ignoreUnknownAttributes(), s); 159 } 160} 161