Analyzer.java revision fc340a20c201bec9c0ee31ec16c85766477a1edf
1e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/*******************************************************************************
237115f4ba4f6126b8c3352ac890c653e428a7dd8Marc R. Hoffmann * Copyright (c) 2009, 2013 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;
20e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport 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;
26fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmannimport org.jacoco.core.internal.Pack200Streams;
27e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.analysis.ClassAnalyzer;
28e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.analysis.StringPool;
29e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.data.CRC64;
30e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.flow.ClassProbesAdapter;
31e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.objectweb.asm.ClassReader;
32e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.objectweb.asm.ClassVisitor;
33e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
34e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/**
35e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * An {@link Analyzer} instance processes a set of Java class files and
36e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * calculates coverage data for them. For each class file the result is reported
37e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * to a given {@link ICoverageVisitor} instance. In addition the
38e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * {@link Analyzer} requires a {@link ExecutionDataStore} instance that holds
39e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * the execution data for the classes to analyze. The {@link Analyzer} offers
40e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * several methods to analyze classes from a variety of sources.
41e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */
42e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpublic class Analyzer {
43e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
44e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private final ExecutionDataStore executionData;
45e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
46e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private final ICoverageVisitor coverageVisitor;
47e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
48e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private final StringPool stringPool;
49e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
50e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
51e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Creates a new analyzer reporting to the given output.
52e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
53e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param executionData
54e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            execution data
55e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param coverageVisitor
56e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            the output instance that will coverage data for every analyzed
57e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            class
58e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
59e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public Analyzer(final ExecutionDataStore executionData,
60e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			final ICoverageVisitor coverageVisitor) {
61e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.executionData = executionData;
62e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.coverageVisitor = coverageVisitor;
63e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.stringPool = new StringPool();
64e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
65e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
66e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
67e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Creates an ASM class visitor for analysis.
68e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
69e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param classid
70e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            id of the class calculated with {@link CRC64}
71e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return ASM visitor to write class definition to
72e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
73e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private ClassVisitor createAnalyzingVisitor(final long classid) {
74e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		final ExecutionData data = executionData.get(classid);
7527e32e433ba0ac1fdec9290d3454d5b369c969ccMarc R. Hoffmann		final boolean[] probes = data == null ? null : data.getProbes();
7627e32e433ba0ac1fdec9290d3454d5b369c969ccMarc R. Hoffmann		final ClassAnalyzer analyzer = new ClassAnalyzer(classid, probes,
77e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				stringPool) {
78e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			@Override
79e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			public void visitEnd() {
80e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				super.visitEnd();
81e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				coverageVisitor.visitCoverage(getCoverage());
82e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			}
83e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		};
84e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return new ClassProbesAdapter(analyzer);
85e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
86e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
87e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
88e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Analyzes the class given as a ASM reader.
89e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
90e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param reader
91e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            reader with class definitions
92e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
93e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public void analyzeClass(final ClassReader reader) {
94e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		final ClassVisitor visitor = createAnalyzingVisitor(CRC64
95e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				.checksum(reader.b));
96e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		reader.accept(visitor, 0);
97e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
98e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
99e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
100e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Analyzes the class definition from a given in-memory buffer.
101e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
102e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param buffer
103e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            class definitions
104e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
105e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public void analyzeClass(final byte[] buffer) {
106e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		analyzeClass(new ClassReader(buffer));
107e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
108e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
109e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
110e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Analyzes the class definition from a given input stream.
111e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
112e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param input
113e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            stream to read class definition from
114e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
11557f7cf06888f1e34f9ab2e3129c3d433826ecbe1Marc R. Hoffmann	 *             if the stream can't be read
116e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
117e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public void analyzeClass(final InputStream input) throws IOException {
118e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		analyzeClass(new ClassReader(input));
119e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
120e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
121e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
122e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Analyzes all classes contained in the ZIP archive (jar, war, ear, etc.)
123e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * given as an input stream. Contained archives are read recursively.
124e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
125e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param input
126e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            ZIP archive data
127e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return number of class files found
128e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
12957f7cf06888f1e34f9ab2e3129c3d433826ecbe1Marc R. Hoffmann	 *             if the stream can't be read
130fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	 * @deprecated Use {@link #analyzeAll(InputStream)} instead
131e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
132fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	@Deprecated
133e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public int analyzeArchive(final InputStream input) throws IOException {
134fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		return analyzeZip(input);
135e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
136e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
137e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
138e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Analyzes all classes found in the given input stream. The input stream
139fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	 * may either represent a single class file, a ZIP archive, a Pack200
140fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	 * archive or a gzip stream that is searched recursively for class files.
141fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	 * All other content types are ignored.
142e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
143e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param input
144e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            input data
145e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return number of class files found
146e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
14757f7cf06888f1e34f9ab2e3129c3d433826ecbe1Marc R. Hoffmann	 *             if the stream can't be read
148e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
149e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public int analyzeAll(final InputStream input) throws IOException {
150e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		final ContentTypeDetector detector = new ContentTypeDetector(input);
151e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		switch (detector.getType()) {
152e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		case ContentTypeDetector.CLASSFILE:
153e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			analyzeClass(detector.getInputStream());
154e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			return 1;
155e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		case ContentTypeDetector.ZIPFILE:
156fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann			return analyzeZip(detector.getInputStream());
157fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		case ContentTypeDetector.GZFILE:
158fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann			return analyzeGzip(detector.getInputStream());
159fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		case ContentTypeDetector.PACK200FILE:
160fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann			return analyzePack200(detector.getInputStream());
161e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		default:
162e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			return 0;
163e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
164e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
165e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
166e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
167e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Analyzes all class files contained in the given file or folder. Class
168e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * files as well as ZIP files are considered. Folders are searched
169e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * recursively.
170e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
171e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param file
172e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            file or folder to look for class files
173e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return number of class files found
174e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
17557f7cf06888f1e34f9ab2e3129c3d433826ecbe1Marc R. Hoffmann	 *             if the file can't be read
176e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
177e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public int analyzeAll(final File file) throws IOException {
178e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		int count = 0;
179e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		if (file.isDirectory()) {
180e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			for (final File f : file.listFiles()) {
181e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				count += analyzeAll(f);
182e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			}
183e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		} else {
184e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			final InputStream in = new FileInputStream(file);
185e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			try {
186e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				count += analyzeAll(in);
187e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			} finally {
188e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				in.close();
189e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			}
190e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
191e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return count;
192e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
193e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
194e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
195e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Analyzes all classes from the given class path. Directories containing
196e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * class files as well as archive files are considered.
197e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
198e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param path
199e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            path definition
200e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param basedir
201e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            optional base directory, if <code>null</code> the current
202e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            working directory is used as the base for relative path
203e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            entries
204e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return number of class files found
205e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
20657f7cf06888f1e34f9ab2e3129c3d433826ecbe1Marc R. Hoffmann	 *             if a file can't be read
207e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
208e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public int analyzeAll(final String path, final File basedir)
209e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throws IOException {
210e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		int count = 0;
211e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		final StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
212e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		while (st.hasMoreTokens()) {
213e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			count += analyzeAll(new File(basedir, st.nextToken()));
214e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
215e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return count;
216e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
217e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
218fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	private int analyzeZip(final InputStream input) throws IOException {
219fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		final ZipInputStream zip = new ZipInputStream(input);
220fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		int count = 0;
221fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		while (true) {
222fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann			final ZipEntry entry = zip.getNextEntry();
223fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann			if (entry == null) {
224fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann				break;
225fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann			}
226fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann			count += analyzeAll(zip);
227fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		}
228fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		return count;
229fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	}
230fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann
231fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	private int analyzeGzip(final InputStream input) throws IOException {
232fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		return analyzeAll(new GZIPInputStream(input));
233fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	}
234fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann
235fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	private int analyzePack200(final InputStream input) throws IOException {
236fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann		return analyzeAll(Pack200Streams.unpack(input));
237fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann	}
238fc340a20c201bec9c0ee31ec16c85766477a1edfMarc R. Hoffmann
239e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov}
240