/* * sulky-modules - several general-purpose modules. * Copyright (C) 2007-2017 Joern Huxhorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright 2007-2017 Joern Huxhorn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.huxhorn.sulky.version; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class ClassFileScanner { private final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ClassFileScanner.class); private static final String CLASS_EXTENSION = ".class"; private static final int MAGIC_NUMBER_CLASS = 0xCAFEBABE; private final List<ClassStatisticMapper> classStatisticMappers =new ArrayList<ClassStatisticMapper>(); public List<ClassStatisticMapper> getClassStatisticMappers() { return classStatisticMappers; } public void reset() { for (ClassStatisticMapper classStatisticMapper : classStatisticMappers) { classStatisticMapper.reset(); } } public void scanDirectory(File directory) throws IOException { if(!directory.isDirectory()) { throw new IllegalArgumentException("'directory' must be a directory!"); } String source = directory.getName(); scanDirectory(directory, source); } public void scanDirectory(File directory, String source) throws IOException { if(!directory.isDirectory()) { throw new IllegalArgumentException("'directory' must be a directory!"); } if(source == null) { throw new NullPointerException("'source' must not be null!"); } String absoluteBasePath = directory.getAbsolutePath(); absoluteBasePath = absoluteBasePath.replace('\\', '/'); absoluteBasePath = absoluteBasePath+"/"; File[] files = directory.listFiles(); if(files == null) { return; } for (File current : files) { processFile(absoluteBasePath, current, source); } } private void processFile(String absoluteBasePath, File file, String source) throws IOException { if(file.isDirectory()) { File[] files = file.listFiles(); if(files == null) { return; } for (File current : files) { processFile(absoluteBasePath, current, source); } } if(file.isFile()) { String absoluteFilePath = file.getAbsolutePath(); absoluteFilePath = absoluteFilePath.replace('\\', '/'); if (!absoluteFilePath.endsWith(CLASS_EXTENSION)) { return; } String classFileName = absoluteFilePath.substring(absoluteBasePath.length()); FileInputStream input = null; try { // not changed to Files.newInputStream() because targetCompatibility = 1.5 input = new FileInputStream(file); scanClass(input, classFileName, source); } finally { if(input != null) { try { input.close(); } catch (IOException ex) { // ignore } } } } } public void scanJar(File jarFile) throws IOException { String sourceName = jarFile.getName(); ZipFile zipFile = null; try { zipFile = new ZipFile(jarFile); Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry current = entries.nextElement(); if (current.isDirectory()) { continue; } String currentName = current.getName(); if (!currentName.endsWith(CLASS_EXTENSION)) { continue; } InputStream classStream = zipFile.getInputStream(current); if (classStream == null) { continue; } try { scanClass(classStream, currentName, sourceName); } catch (IOException ex) { // ignore } finally { try { classStream.close(); } catch (IOException ex) { // ignore } } } } finally { if (zipFile != null) { try { zipFile.close(); } catch (IOException ex) { // ignore } } } } private void scanClass(InputStream is, String classFileName, String sourceName) throws IOException { if (!classFileName.endsWith(CLASS_EXTENSION)) { return; } DataInputStream dis = new DataInputStream(is); int magic = dis.readInt(); if(MAGIC_NUMBER_CLASS != magic) { if(logger.isDebugEnabled()) logger.debug("Wrong magic number for class in {}. Ignoring.", classFileName); return; } /*char minor = */dis.readChar(); char currentMajor = dis.readChar(); int slashIndex = classFileName.lastIndexOf('/'); String packageString=""; String className = classFileName; if(slashIndex >= 0) { packageString = classFileName.substring(0, slashIndex); packageString = packageString.replace('/','.'); className = classFileName.substring(slashIndex+1); } className = className.substring(0, className.length()-CLASS_EXTENSION.length()); for (ClassStatisticMapper current : classStatisticMappers) { current.evaluate(sourceName, packageString, className, currentMajor); } } }