ClassPath.java revision 0
869N/A/*
869N/A * Copyright 1994-2007 Sun Microsystems, Inc. All Rights Reserved.
869N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
869N/A *
869N/A * This code is free software; you can redistribute it and/or modify it
869N/A * under the terms of the GNU General Public License version 2 only, as
869N/A * published by the Free Software Foundation. Sun designates this
869N/A * particular file as subject to the "Classpath" exception as provided
869N/A * by Sun in the LICENSE file that accompanied this code.
869N/A *
869N/A * This code is distributed in the hope that it will be useful, but WITHOUT
869N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
869N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
869N/A * version 2 for more details (a copy is included in the LICENSE file that
869N/A * accompanied this code).
869N/A *
869N/A * You should have received a copy of the GNU General Public License version
873N/A * 2 along with this work; if not, write to the Free Software Foundation,
869N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
869N/A *
869N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
869N/A * CA 95054 USA or visit www.sun.com if you need additional information or
869N/A * have any questions.
869N/A */
869N/A
0N/Apackage sun.tools.java;
0N/A
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.Hashtable;
869N/Aimport java.io.File;
0N/Aimport java.io.IOException;
0N/Aimport java.util.zip.*;
0N/A
869N/A/**
0N/A * This class is used to represent a class path, which can contain both
869N/A * directories and zip files.
0N/A *
869N/A * WARNING: The contents of this source file are not part of any
869N/A * supported API. Code that depends on them does so at its own risk:
869N/A * they are subject to change or removal without notice.
0N/A */
869N/Apublic
48N/Aclass ClassPath {
869N/A static final char dirSeparator = File.pathSeparatorChar;
0N/A
869N/A /**
716N/A * The original class path string
869N/A */
1958N/A String pathstr;
1963N/A
2340N/A /**
1954N/A * List of class path entries
1954N/A */
1954N/A private ClassPathEntry[] path;
1954N/A
1954N/A /**
1954N/A * Build a class path from the specified path string
1954N/A */
1954N/A public ClassPath(String pathstr) {
2350N/A init(pathstr);
1954N/A }
1954N/A
1954N/A /**
1954N/A * Build a class path from the specified array of class path
0N/A * element strings. This constructor, and the corresponding
0N/A * "init" method, were added as part of the fix for 6473331, which
869N/A * adds support for Class-Path manifest entries in JAR files to
868N/A * rmic. It is conceivable that the value of a Class-Path
983N/A * manifest entry will contain a path separator, which would cause
1928N/A * incorrect behavior if the expanded path were passed to the
2042N/A * previous constructor as a single path-separator-delimited
1004N/A * string; use of this constructor avoids that problem.
1007N/A */
1378N/A public ClassPath(String[] patharray) {
1411N/A init(patharray);
1503N/A }
869N/A
1774N/A /**
1004N/A * Build a default class path from the path strings specified by
0N/A * the properties sun.boot.class.path and env.class.path, in that
2270N/A * order.
2270N/A */
2270N/A public ClassPath() {
2270N/A String syscp = System.getProperty("sun.boot.class.path");
2270N/A String envcp = System.getProperty("env.class.path");
2270N/A if (envcp == null) envcp = ".";
2270N/A String cp = syscp + File.pathSeparator + envcp;
0N/A init(cp);
869N/A }
868N/A
0N/A private void init(String pathstr) {
0N/A int i, j, n;
65N/A // Save original class path string
869N/A this.pathstr = pathstr;
868N/A
65N/A if (pathstr.length() == 0) {
869N/A this.path = new ClassPathEntry[0];
65N/A }
65N/A
65N/A // Count the number of path separators
65N/A i = n = 0;
65N/A while ((i = pathstr.indexOf(dirSeparator, i)) != -1) {
65N/A n++; i++;
65N/A }
65N/A // Build the class path
65N/A ClassPathEntry[] path = new ClassPathEntry[n+1];
65N/A int len = pathstr.length();
65N/A for (i = n = 0; i < len; i = j + 1) {
65N/A if ((j = pathstr.indexOf(dirSeparator, i)) == -1) {
65N/A j = len;
65N/A }
65N/A if (i == j) {
2266N/A path[n] = new ClassPathEntry();
2266N/A path[n++].dir = new File(".");
2266N/A } else {
2266N/A File file = new File(pathstr.substring(i, j));
2266N/A if (file.isFile()) {
2266N/A try {
2266N/A ZipFile zip = new ZipFile(file);
2266N/A path[n] = new ClassPathEntry();
2266N/A path[n++].zip = zip;
2266N/A } catch (ZipException e) {
2266N/A } catch (IOException e) {
2266N/A // Ignore exceptions, at least for now...
2266N/A }
2266N/A } else {
2266N/A path[n] = new ClassPathEntry();
2266N/A path[n++].dir = file;
2266N/A }
2266N/A }
2266N/A }
2266N/A // Trim class path to exact size
2266N/A this.path = new ClassPathEntry[n];
2266N/A System.arraycopy((Object)path, 0, (Object)this.path, 0, n);
2266N/A }
2266N/A
2266N/A private void init(String[] patharray) {
2266N/A // Save original class path string
2266N/A if (patharray.length == 0) {
2266N/A this.pathstr = "";
2266N/A } else {
2266N/A StringBuilder sb = new StringBuilder(patharray[0]);
2266N/A for (int i = 1; i < patharray.length; i++) {
2266N/A sb.append(File.separator);
2266N/A sb.append(patharray[i]);
2266N/A }
2266N/A this.pathstr = sb.toString();
0N/A }
869N/A
868N/A // Build the class path
0N/A ClassPathEntry[] path = new ClassPathEntry[patharray.length];
0N/A int n = 0;
0N/A for (String name : patharray) {
0N/A File file = new File(name);
0N/A if (file.isFile()) {
2334N/A try {
0N/A ZipFile zip = new ZipFile(file);
0N/A path[n] = new ClassPathEntry();
1501N/A path[n++].zip = zip;
0N/A } catch (ZipException e) {
0N/A } catch (IOException e) {
869N/A // Ignore exceptions, at least for now...
868N/A }
0N/A } else {
0N/A path[n] = new ClassPathEntry();
869N/A path[n++].dir = file;
0N/A }
0N/A }
869N/A // Trim class path to exact size
868N/A this.path = new ClassPathEntry[n];
869N/A System.arraycopy((Object)path, 0, (Object)this.path, 0, n);
869N/A }
868N/A
868N/A /**
869N/A * Find the specified directory in the class path
869N/A */
0N/A public ClassFile getDirectory(String name) {
0N/A return getFile(name, true);
1790N/A }
48N/A
869N/A /**
869N/A * Load the specified file from the class path
869N/A */
868N/A public ClassFile getFile(String name) {
869N/A return getFile(name, false);
868N/A }
869N/A
2329N/A private final String fileSeparatorChar = "" + File.separatorChar;
1155N/A
1155N/A private ClassFile getFile(String name, boolean isDirectory) {
1155N/A String subdir = name;
1155N/A String basename = "";
1155N/A if (!isDirectory) {
1155N/A int i = name.lastIndexOf(File.separatorChar);
1155N/A subdir = name.substring(0, i + 1);
1155N/A basename = name.substring(i + 1);
1155N/A } else if (!subdir.equals("")
1155N/A && !subdir.endsWith(fileSeparatorChar)) {
1155N/A // zip files are picky about "foo" vs. "foo/".
1155N/A // also, the getFiles caches are keyed with a trailing /
1155N/A subdir = subdir + File.separatorChar;
1155N/A name = subdir; // Note: isDirectory==true & basename==""
1155N/A }
0N/A for (int i = 0; i < path.length; i++) {
0N/A if (path[i].zip != null) {
869N/A String newname = name.replace(File.separatorChar, '/');
868N/A ZipEntry entry = path[i].zip.getEntry(newname);
0N/A if (entry != null) {
0N/A return new ClassFile(path[i].zip, entry);
848N/A }
848N/A } else {
848N/A File file = new File(path[i].dir.getPath(), name);
869N/A String list[] = path[i].getFiles(subdir);
868N/A if (isDirectory) {
848N/A if (list.length > 0) {
0N/A return new ClassFile(file);
0N/A }
0N/A } else {
869N/A for (int j = 0; j < list.length; j++) {
0N/A if (basename.equals(list[j])) {
0N/A // Don't bother checking !file.isDir,
0N/A // since we only look for names which
868N/A // cannot already be packages (foo.java, etc).
2222N/A return new ClassFile(file);
2222N/A }
2222N/A }
2222N/A }
2222N/A }
2222N/A }
2222N/A return null;
2222N/A }
2222N/A
2222N/A /**
2222N/A * Returns list of files given a package name and extension.
2222N/A */
868N/A public Enumeration getFiles(String pkg, String ext) {
868N/A Hashtable files = new Hashtable();
868N/A for (int i = path.length; --i >= 0; ) {
869N/A if (path[i].zip != null) {
868N/A Enumeration e = path[i].zip.entries();
115N/A while (e.hasMoreElements()) {
868N/A ZipEntry entry = (ZipEntry)e.nextElement();
868N/A String name = entry.getName();
868N/A name = name.replace('/', File.separatorChar);
868N/A if (name.startsWith(pkg) && name.endsWith(ext)) {
868N/A files.put(name, new ClassFile(path[i].zip, entry));
869N/A }
868N/A }
868N/A } else {
868N/A String[] list = path[i].getFiles(pkg);
868N/A for (int j = 0; j < list.length; j++) {
868N/A String name = list[j];
868N/A if (name.endsWith(ext)) {
868N/A name = pkg + File.separatorChar + name;
869N/A File file = new File(path[i].dir.getPath(), name);
868N/A files.put(name, new ClassFile(file));
868N/A }
868N/A }
868N/A }
868N/A }
869N/A return files.elements();
868N/A }
868N/A
868N/A /**
868N/A * Release resources.
868N/A */
869N/A public void close() throws IOException {
868N/A for (int i = path.length; --i >= 0; ) {
868N/A if (path[i].zip != null) {
868N/A path[i].zip.close();
868N/A }
868N/A }
868N/A }
868N/A
869N/A /**
868N/A * Returns original class path string
868N/A */
868N/A public String toString() {
868N/A return pathstr;
868N/A }
868N/A}
868N/A
869N/A/**
868N/A * A class path entry, which can either be a directory or an open zip file.
0N/A */
2222N/Aclass ClassPathEntry {
0N/A File dir;
868N/A ZipFile zip;
2222N/A
868N/A Hashtable subdirs = new Hashtable(29); // cache of sub-directory listings
868N/A String[] getFiles(String subdir) {
1948N/A String files[] = (String[]) subdirs.get(subdir);
1948N/A if (files == null) {
1948N/A // search the directory, exactly once
1948N/A File sd = new File(dir.getPath(), subdir);
1948N/A if (sd.isDirectory()) {
869N/A files = sd.list();
869N/A if (files == null) {
869N/A // should not happen, but just in case, fail silently
869N/A files = new String[0];
869N/A }
869N/A if (files.length == 0) {
869N/A String nonEmpty[] = { "" };
869N/A files = nonEmpty;
869N/A }
869N/A } else {
869N/A files = new String[0];
869N/A }
869N/A subdirs.put(subdir, files);
869N/A }
2334N/A return files;
869N/A }
869N/A
869N/A}
869N/A