1e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/******************************************************************************* 2b9d1b54e300318b470d9fedccc69d75187016444Evgeny Mandrikov * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors 3e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * All rights reserved. This program and the accompanying materials 4e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * are made available under the terms of the Eclipse Public License v1.0 5e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * which accompanies this distribution, and is available at 6e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * http://www.eclipse.org/legal/epl-v10.html 7e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 8e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Contributors: 9e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Marc R. Hoffmann - initial API and implementation 10e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 11e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *******************************************************************************/ 12e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpackage org.jacoco.core.analysis; 13e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 14e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.File; 15e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.FileInputStream; 16e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.IOException; 17e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.InputStream; 18e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.util.StringTokenizer; 19fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmannimport java.util.zip.GZIPInputStream; 20ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmannimport java.util.zip.ZipEntry; 21e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.util.zip.ZipInputStream; 22e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 23e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.data.ExecutionData; 24e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.data.ExecutionDataStore; 25adf2bf660e12b3b284eb80965328802101cf6762Marc R. Hoffmannimport org.jacoco.core.internal.ContentTypeDetector; 26caa820ed62133f47bacba06ea931bf5d7c43dcd6Roberto Araujoimport org.jacoco.core.internal.InputStreams; 27fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmannimport org.jacoco.core.internal.Pack200Streams; 28e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.analysis.ClassAnalyzer; 29f4622217085198f3ae42906934026961b29d1111Marc R. Hoffmannimport org.jacoco.core.internal.analysis.ClassCoverageImpl; 30e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.analysis.StringPool; 31e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.data.CRC64; 32e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.flow.ClassProbesAdapter; 33e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.objectweb.asm.ClassReader; 34e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.objectweb.asm.ClassVisitor; 35e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 36e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/** 37e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * An {@link Analyzer} instance processes a set of Java class files and 38e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * calculates coverage data for them. For each class file the result is reported 39e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * to a given {@link ICoverageVisitor} instance. In addition the 40e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * {@link Analyzer} requires a {@link ExecutionDataStore} instance that holds 41e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * the execution data for the classes to analyze. The {@link Analyzer} offers 42e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * several methods to analyze classes from a variety of sources. 43e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 44e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpublic class Analyzer { 45e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 46e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final ExecutionDataStore executionData; 47e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 48e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final ICoverageVisitor coverageVisitor; 49e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 50e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final StringPool stringPool; 51e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 52e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 53e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Creates a new analyzer reporting to the given output. 54e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 55e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param executionData 56e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * execution data 57e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param coverageVisitor 58e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * the output instance that will coverage data for every analyzed 59e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * class 60e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 61e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public Analyzer(final ExecutionDataStore executionData, 62e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final ICoverageVisitor coverageVisitor) { 63e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this.executionData = executionData; 64e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this.coverageVisitor = coverageVisitor; 65e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this.stringPool = new StringPool(); 66e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 67e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 68e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 69e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Creates an ASM class visitor for analysis. 70e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 71e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param classid 72e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * id of the class calculated with {@link CRC64} 7360c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann * @param className 7460c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann * VM name of the class 75e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @return ASM visitor to write class definition to 76e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 7760c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann private ClassVisitor createAnalyzingVisitor(final long classid, 7860c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann final String className) { 79e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final ExecutionData data = executionData.get(classid); 8060c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann final boolean[] probes; 8160c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann final boolean noMatch; 8260c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann if (data == null) { 8360c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann probes = null; 8460c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann noMatch = executionData.contains(className); 8560c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann } else { 8660c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann probes = data.getProbes(); 8760c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann noMatch = false; 8860c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann } 89f4622217085198f3ae42906934026961b29d1111Marc R. Hoffmann final ClassCoverageImpl coverage = new ClassCoverageImpl(className, 90f4622217085198f3ae42906934026961b29d1111Marc R. Hoffmann classid, noMatch); 91f4622217085198f3ae42906934026961b29d1111Marc R. Hoffmann final ClassAnalyzer analyzer = new ClassAnalyzer(coverage, probes, 92f4622217085198f3ae42906934026961b29d1111Marc R. Hoffmann stringPool) { 93e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov @Override 94e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public void visitEnd() { 95e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov super.visitEnd(); 96f4622217085198f3ae42906934026961b29d1111Marc R. Hoffmann coverageVisitor.visitCoverage(coverage); 97e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 98e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov }; 998f81097f70a2b9c570e225dec4dcf3a28b988efcMarc R. Hoffmann return new ClassProbesAdapter(analyzer, false); 100e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 101e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 102e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 103e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Analyzes the class given as a ASM reader. 104e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 105e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param reader 106e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * reader with class definitions 107e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 108e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public void analyzeClass(final ClassReader reader) { 10960c33d63e75c1b0a5da9bd58be1f0b5434240220Marc R. Hoffmann final ClassVisitor visitor = createAnalyzingVisitor( 1100c50b210738a2d3facb53598a7208d456f214364Evgeny Mandrikov CRC64.classId(reader.b), reader.getClassName()); 111e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov reader.accept(visitor, 0); 112e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 113e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 114e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 115e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Analyzes the class definition from a given in-memory buffer. 116e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 117e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param buffer 118e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * class definitions 119024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann * @param location 120024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann * a location description used for exception messages 121ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann * @throws IOException 122ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann * if the class can't be analyzed 123e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 124024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann public void analyzeClass(final byte[] buffer, final String location) 125ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann throws IOException { 126ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann try { 127caa820ed62133f47bacba06ea931bf5d7c43dcd6Roberto Araujo analyzeClass(new ClassReader(buffer)); 128ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann } catch (final RuntimeException cause) { 129024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann throw analyzerError(location, cause); 130ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann } 131e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 132e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 133e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 13411ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann * Analyzes the class definition from a given input stream. The provided 13511ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann * {@link InputStream} is not closed by this method. 136e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 137e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param input 138e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * stream to read class definition from 139024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann * @param location 140024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann * a location description used for exception messages 141e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 142ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann * if the stream can't be read or the class can't be analyzed 143e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 144024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann public void analyzeClass(final InputStream input, final String location) 145ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann throws IOException { 1461b959434976cccd90c8504a6f8a721151f5ff8afEvgeny Mandrikov final byte[] buffer; 147ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann try { 148caa820ed62133f47bacba06ea931bf5d7c43dcd6Roberto Araujo buffer = InputStreams.readFully(input); 1491b959434976cccd90c8504a6f8a721151f5ff8afEvgeny Mandrikov } catch (final IOException e) { 150024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann throw analyzerError(location, e); 151ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann } 1521b959434976cccd90c8504a6f8a721151f5ff8afEvgeny Mandrikov analyzeClass(buffer, location); 153e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 154e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 155024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann private IOException analyzerError(final String location, 156fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov final Exception cause) { 15711ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann final IOException ex = new IOException( 15811ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann String.format("Error while analyzing %s.", location)); 159ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann ex.initCause(cause); 160ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann return ex; 161e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 162e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 163e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 164e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Analyzes all classes found in the given input stream. The input stream 165fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann * may either represent a single class file, a ZIP archive, a Pack200 166fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann * archive or a gzip stream that is searched recursively for class files. 16711ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann * All other content types are ignored. The provided {@link InputStream} is 16811ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann * not closed by this method. 169e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 170e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param input 171e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * input data 172024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann * @param location 173024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann * a location description used for exception messages 174e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @return number of class files found 175e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 176ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann * if the stream can't be read or a class can't be analyzed 177e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 178024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann public int analyzeAll(final InputStream input, final String location) 179ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann throws IOException { 180fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov final ContentTypeDetector detector; 181fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov try { 182fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov detector = new ContentTypeDetector(input); 18311ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann } catch (final IOException e) { 184fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov throw analyzerError(location, e); 185fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov } 186e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov switch (detector.getType()) { 187e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov case ContentTypeDetector.CLASSFILE: 188024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann analyzeClass(detector.getInputStream(), location); 189e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return 1; 190e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov case ContentTypeDetector.ZIPFILE: 191024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann return analyzeZip(detector.getInputStream(), location); 192fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann case ContentTypeDetector.GZFILE: 193024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann return analyzeGzip(detector.getInputStream(), location); 194fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann case ContentTypeDetector.PACK200FILE: 195024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann return analyzePack200(detector.getInputStream(), location); 196e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov default: 197e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return 0; 198e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 199e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 200e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 201e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 202e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Analyzes all class files contained in the given file or folder. Class 203e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * files as well as ZIP files are considered. Folders are searched 204e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * recursively. 205e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 206e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param file 207e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * file or folder to look for class files 208e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @return number of class files found 209e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 210ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann * if the file can't be read or a class can't be analyzed 211e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 212e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public int analyzeAll(final File file) throws IOException { 213e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov int count = 0; 214e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov if (file.isDirectory()) { 215e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov for (final File f : file.listFiles()) { 216e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov count += analyzeAll(f); 217e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 218e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } else { 219e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final InputStream in = new FileInputStream(file); 220e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov try { 221ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann count += analyzeAll(in, file.getPath()); 222e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } finally { 223e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov in.close(); 224e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 225e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 226e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return count; 227e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 228e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 229e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 230e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Analyzes all classes from the given class path. Directories containing 231e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * class files as well as archive files are considered. 232e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 233e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param path 234e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * path definition 235e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param basedir 236e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * optional base directory, if <code>null</code> the current 237e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * working directory is used as the base for relative path 238e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * entries 239e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @return number of class files found 240e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 241ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann * if a file can't be read or a class can't be analyzed 242e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 243e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public int analyzeAll(final String path, final File basedir) 244e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov throws IOException { 245e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov int count = 0; 246fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov final StringTokenizer st = new StringTokenizer(path, 247fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov File.pathSeparator); 248e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov while (st.hasMoreTokens()) { 249e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov count += analyzeAll(new File(basedir, st.nextToken())); 250e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 251e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return count; 252e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 253e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 254024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann private int analyzeZip(final InputStream input, final String location) 255ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann throws IOException { 256fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann final ZipInputStream zip = new ZipInputStream(input); 257ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann ZipEntry entry; 258fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann int count = 0; 259fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov while ((entry = nextEntry(zip, location)) != null) { 260024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann count += analyzeAll(zip, location + "@" + entry.getName()); 261fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann } 262fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann return count; 263fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann } 264fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann 26511ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann private ZipEntry nextEntry(final ZipInputStream input, 26611ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann final String location) throws IOException { 267fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov try { 268fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov return input.getNextEntry(); 26911ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann } catch (final IOException e) { 270fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov throw analyzerError(location, e); 271fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov } 272fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov } 273fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov 274024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann private int analyzeGzip(final InputStream input, final String location) 275ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann throws IOException { 276fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov GZIPInputStream gzipInputStream; 277fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov try { 278fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov gzipInputStream = new GZIPInputStream(input); 27911ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann } catch (final IOException e) { 280fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov throw analyzerError(location, e); 281fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov } 282fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov return analyzeAll(gzipInputStream, location); 283fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann } 284fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann 285024536619572c1ad5274cbe6872ea8068a9498acMarc R. Hoffmann private int analyzePack200(final InputStream input, final String location) 286ac07e252571819685d3f74cb69c90c23abd340a0Marc R. Hoffmann throws IOException { 287fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov InputStream unpackedInput; 288fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov try { 289fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov unpackedInput = Pack200Streams.unpack(input); 29011ac066394b176096f48516d8c6b486648ba24c6Marc R. Hoffmann } catch (final IOException e) { 291fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov throw analyzerError(location, e); 292fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov } 293fde254dd251e6afc1c8f1272efb1be2b6c767387Evgeny Mandrikov return analyzeAll(unpackedInput, location); 294fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann } 295fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann 296e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov} 297