Codebase list libcodesize-java / 8174d4f
Imported Upstream version 1.1 Markus Koschany 9 years ago
2 changed file(s) with 469 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Manifest-Version: 1.0
1 Archiver-Version: Plexus Archiver
2 Created-By: Apache Maven
3 Built-By: Downlord
4 Build-Jdk: 1.7.0
5
0 /*******************************************************************************
1 * Copyright (c) 2002, 2007 Christian D. Schnell, Flemming N. Larsen
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Common Public License v1.0
4 * which accompanies this distribution, and is available at
5 * http://robocode.sourceforge.net/license/cpl-v10.html
6 *
7 * Contributors:
8 * Christian D. Schnell
9 * - Initial API and implementation
10 * Flemming N. Larsen
11 * - Changed to a dynamic buffer when processing .jar files based on the size
12 * of the .jar file
13 * - Added the getByteArrayOutputStream() as helper method
14 * - Extended the processZipFile(File, ZipInputStream) to take nested .jar
15 * files into account
16 * - Added Javadoc comments to all classes and methods
17 *******************************************************************************/
18 package codesize;
19
20 import java.io.BufferedInputStream;
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.PrintStream;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.zip.ZipEntry;
32 import java.util.zip.ZipInputStream;
33
34 import org.apache.bcel.classfile.ClassParser;
35 import org.apache.bcel.classfile.Code;
36 import org.apache.bcel.classfile.Method;
37
38 /**
39 * Codesize is a tool for calculating the code size of a Java class file or Java
40 * archive (JAR).
41 *
42 * @author Christian D. Schnell (original)
43 * @author Flemming N. Larsen (contributor)
44 */
45 public class Codesize {
46 private final static int DEFAULT_BUFFER_SIZE = 512 * 1024; // 512 KB
47
48 private static boolean verbose;
49
50 private Codesize() {
51 }
52
53 /**
54 * Container which keeps information extracted by Codesize.
55 *
56 * @author Christian D. Schnell
57 *
58 * @see Codesize#processClassFile(File)
59 * @see Codesize#processDirectory(File)
60 * @see Codesize#processZipFile(File)
61 * @see Codesize#processZipFile(File, ZipInputStream)
62 */
63 public static class Item implements Comparable {
64 private final File location;
65 private final int nClassFiles, ttlClassSize, ttlCodeSize;
66
67 Item(File location, int nClassFiles, int ttlClassSize, int ttlCodeSize) {
68 this.location = location;
69 this.nClassFiles = nClassFiles;
70 this.ttlClassSize = ttlClassSize;
71 this.ttlCodeSize = ttlCodeSize;
72 }
73
74 /**
75 * Returns the file location of the item.
76 *
77 * @return a File containing the file location
78 */
79 public File getLocation() {
80 return location;
81 }
82
83 /**
84 * Returns the number of found class files.
85 *
86 * @return the number of found class files
87 */
88 public int getNClassFiles() {
89 return nClassFiles;
90 }
91
92 /**
93 * Returns the total size of all found class files.
94 *
95 * @return the total size of all found class files
96 */
97 public int getClassSize() {
98 return ttlClassSize;
99 }
100
101 /**
102 * Returns the total code size of all found class files.
103 *
104 * @return the total code size of all found class files
105 */
106 public int getCodeSize() {
107 return ttlCodeSize;
108 }
109
110 /**
111 * Compares this item with another item based on their code sizes.
112 *
113 * @param item
114 * the item to be compared
115 *
116 * @return a negative integer, zero, or a positive integer as this item is
117 * less than, equal to, or greater than the specified item.
118 */
119 public int compareTo(Object item) {
120 return ttlCodeSize - ((Item) item).ttlCodeSize;
121 }
122 }
123
124 /**
125 * Processes the arguments given from a command line.
126 *
127 * @param args
128 * the arguments given from the command line
129 *
130 * @return a list of retrived Codesize items
131 */
132 private static List processCmdLine(String args[]) {
133 ArrayList result = new ArrayList();
134
135 File file;
136 Item item;
137
138 for (int i = 0; i < args.length; i++) {
139 if (args[i].equals("-v")) {
140 verbose = true;
141 } else if (args[i].equals("-r")) {
142 File repository = new File(args[++i]);
143 String files[] = repository.list();
144
145 for (int j = 0; j < files.length; j++) {
146 file = new File(repository, files[j]);
147 if (files[j].toLowerCase().endsWith(".class")) {
148 item = processClassFile(file);
149 } else {
150 item = processZipFile(file);
151 }
152 if (item != null) {
153 result.add(item);
154 }
155 }
156 } else {
157 file = new File(args[i]);
158 if (file.isDirectory()) {
159 item = processDirectory(file);
160 } else if (args[i].toLowerCase().endsWith(".class")) {
161 item = processClassFile(file);
162 } else {
163 item = processZipFile(file);
164 }
165 if (item != null) {
166 result.add(item);
167 }
168 }
169 }
170
171 Collections.sort(result);
172 return result;
173 }
174
175 /**
176 * Adds all class files that exists under the specified directory and all it's
177 * subdirectories to the specified list of class files.
178 *
179 * @param directory
180 * the directory containing the class files to add
181 * @param result
182 * the list to add all found class files to
183 */
184 private static void deepListClassFiles(File directory, List result) {
185 String files[] = directory.list();
186
187 for (int i = 0; i < files.length; i++) {
188 File file = new File(directory, files[i]);
189
190 if (file.isDirectory()) {
191 deepListClassFiles(file, result);
192 } else if (files[i].toLowerCase().endsWith(".class")) {
193 result.add(file);
194 }
195 }
196 }
197
198 /**
199 * Returns the filename of the specified file.
200 *
201 * @param file
202 * the file to extract the filename from
203 *
204 * @return the filename of the specified file
205 */
206 private static String stripFilename(File file) {
207 String result = file.toString();
208
209 if (result.indexOf(File.separator) > -1) {
210 result = result.substring(result.lastIndexOf(File.separator) + 1);
211 }
212 return result;
213 }
214
215 /**
216 * Prints out the help information for Codesize.
217 */
218 private static void help() {
219 Package p = Codesize.class.getPackage();
220
221 System.out.println(
222 p.getImplementationTitle() + " " + p.getImplementationVersion()
223 + " - http://user.cs.tu-berlin.de/~lulli/codesize/");
224 System.out.println("SYNTAX:");
225 System.out.println();
226 System.out.println(" codesize [-v] [<class-file> | <zip-file> | <directory> | -r <repository>]+");
227 System.out.println();
228 System.out.println("- <class-file> is a single .class file");
229 System.out.println("- <zip-file> is a zip compressed file (or a .jar file)");
230 System.out.println("- <directory> is treated like an uncompressed <zip-file>,");
231 System.out.println(" recursively processing any subdirectories");
232 System.out.println("- <repository> is a directory like '<robocode>/robots':");
233 System.out.println(" - any class file in it is treated like a <class-file>");
234 System.out.println(" - any zip file in it is treated like a <zip-file>");
235 System.out.println(" - any subdirectory is ignored (can't distinguish different robots here)");
236 System.out.println("- specify -v for verbose output");
237 }
238
239 /**
240 * Returns the code size of a class from an InputStream.
241 *
242 * @param inputStream
243 * the input stream of the class
244 * @param filename
245 * the filename of the class
246 *
247 * @return the code size of the class
248 *
249 * @throws IOException
250 */
251 private static int processClassInputStream(InputStream inputStream, String filename) throws IOException {
252 int result = 0;
253
254 ClassParser classParser = new ClassParser(inputStream, filename);
255 Method methods[] = classParser.parse().getMethods();
256
257 for (int i = 0; i < methods.length; i++) {
258 Code code = methods[i].getCode();
259
260 if (code != null) {
261 result += code.getCode().length;
262 }
263 }
264
265 if (verbose) {
266 System.out.println(filename + " code size: " + result);
267 }
268
269 return result;
270 }
271
272 /**
273 * Extracts code size information for a class file.
274 *
275 * @param classFile
276 * the filename of the class file
277 *
278 * @return the extracted Codesize information for the class file
279 */
280 public static Item processClassFile(File classFile) {
281 try {
282 InputStream inputStream = new BufferedInputStream(new FileInputStream(classFile));
283
284 try {
285 return new Item(classFile, 1, (int) classFile.length(),
286 processClassInputStream(inputStream, classFile.getName()));
287 } finally {
288 inputStream.close();
289 }
290 } catch (IOException e) {
291 System.err.println("Ignoring " + stripFilename(classFile) + ": " + e.getMessage());
292 }
293
294 return null;
295 }
296
297 /**
298 * Extracts code size information for a directory.
299 *
300 * @param directory
301 * the filename of the directory
302 *
303 * @return the extracted Codesize information about the directory
304 */
305 public static Item processDirectory(File directory) {
306 int ttlClassSize = 0, ttlCodeSize = 0;
307
308 ArrayList classFiles = new ArrayList();
309
310 deepListClassFiles(directory, classFiles);
311
312 for (int i = 0; i < classFiles.size(); i++) {
313 Item item = processClassFile((File) classFiles.get(i));
314
315 ttlClassSize += item.ttlClassSize;
316 ttlCodeSize += item.ttlCodeSize;
317 }
318
319 return new Item(directory, classFiles.size(), ttlClassSize, ttlCodeSize);
320 }
321
322 /**
323 * Extracts code size information for a zip file.
324 *
325 * @param zipFile
326 * the filename of the zip file
327 *
328 * @return the extracted Codesize information for the zip file
329 */
330 public static Item processZipFile(File zipFile) {
331 if (verbose) {
332 System.out.println("Processing zip file " + zipFile.getName());
333 }
334
335 try {
336 ZipInputStream inputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
337
338 try {
339 return processZipFile(zipFile, inputStream);
340 } finally {
341 inputStream.close();
342 }
343 } catch (IOException e) {
344 System.err.println("Ignoring " + stripFilename(zipFile) + ": " + e.getMessage());
345 }
346 return null;
347 }
348
349 /**
350 * Extracts code size information for a zip file given a ZipInputStream.
351 *
352 * @param zipFile
353 * the filename of the zip file
354 * @param inputStream
355 * the input stream of the zip file
356 *
357 * @return the extracted Codesize information for the zip file
358 */
359 public static Item processZipFile(File zipFile, ZipInputStream inputStream)
360 throws IOException {
361 int nClassFiles = 0, ttlClassSize = 0, ttlCodeSize = 0;
362
363 ZipEntry zipEntry;
364
365 while ((zipEntry = inputStream.getNextEntry()) != null) {
366 String lcName = zipEntry.getName().toLowerCase();
367
368 if (lcName.endsWith(".class")) {
369 ByteArrayOutputStream baos = getByteArrayOutputStream(inputStream, (int) zipFile.length());
370
371 ttlCodeSize += processClassInputStream(new ByteArrayInputStream(baos.toByteArray()), zipEntry.getName());
372 ttlClassSize += baos.size();
373 nClassFiles++;
374 } else if (lcName.endsWith(".jar")) {
375 ByteArrayOutputStream baos = getByteArrayOutputStream(inputStream, (int) zipFile.length());
376 ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(baos.toByteArray()));
377
378 try {
379 Item item = processZipFile(zipFile, zis);
380
381 ttlCodeSize += item.ttlCodeSize;
382 ttlClassSize += item.ttlClassSize;
383 } finally {
384 zis.close();
385 }
386 }
387 }
388
389 if (ttlCodeSize == 0) {
390 throw new IOException("total code size is 0");
391 }
392
393 return new Item(zipFile, nClassFiles, ttlClassSize, ttlCodeSize);
394 }
395
396 /**
397 * Reads all bytes from ZipInputStream and returns a ByteArrayOutputStream
398 * containing all read bytes that can be read.
399 *
400 * @param zis
401 * the ZipInputStream to read from
402 * @param length
403 * the length of the ZipInputStream, or -1 if the length is unknown
404 * @return a ByteArrayOutputStream containing all bytes from the
405 * ZipInputStream
406 * @throws IOException
407 */
408 private static ByteArrayOutputStream getByteArrayOutputStream(ZipInputStream zis, int length) throws IOException {
409 if (length < 0) {
410 length = DEFAULT_BUFFER_SIZE;
411 }
412
413 ByteArrayOutputStream baos = new ByteArrayOutputStream();
414 int nRead;
415
416 byte buf[] = new byte[length];
417
418 while ((nRead = zis.read(buf, 0, length)) > -1) {
419 baos.write(buf, 0, nRead);
420 }
421
422 return baos;
423 }
424
425 /**
426 * Dumps a list of Codesize items to the specified PrintStream.
427 *
428 * @param items
429 * the list of items to print out
430 * @param target
431 * the PrintStream to print the items to
432 */
433 public static void dump(List items, PrintStream target) {
434 target.println("\tCode\tClass\tClass");
435 target.println("Nr\tsize\tsize\tfiles\tLocation");
436 target.println("--------------------------------------------------------------------");
437
438 for (int i = 0; i < items.size(); i++) {
439 Item item = (Item) items.get(i);
440
441 target.println(
442 "" + (i + 1) + "\t" + item.ttlCodeSize + "\t" + item.ttlClassSize + "\t" + item.nClassFiles + "\t"
443 + stripFilename(item.location));
444 }
445 }
446
447 /**
448 * The main entry for running the Codesize tool from the command line.
449 *
450 * @param args
451 * the arguments given from the command line
452 */
453 public static void main(String args[]) {
454 List items = processCmdLine(args);
455
456 if (items.size() == 0) {
457 help();
458 } else {
459 dump(items, System.out);
460 }
461 }
462 }