001    /*
002     * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.file;
027    
028    import java.io.File;
029    import java.util.zip.ZipEntry;
030    import java.util.zip.ZipFile;
031    import javax.tools.JavaFileObject;
032    
033    /**
034     * Used to represent a platform-neutral path within a platform-specific
035     * container, such as a directory or zip file.
036     * Internally, the file separator is always '/'.
037     */
038    public abstract class RelativePath implements Comparable<RelativePath> {
039        /**
040         * @param p must use '/' as an internal separator
041         */
042        protected RelativePath(String p) {
043            path = p;
044        }
045    
046        public abstract RelativeDirectory dirname();
047    
048        public abstract String basename();
049    
050        public File getFile(File directory) {
051            if (path.length() == 0)
052                return directory;
053            return new File(directory, path.replace('/', File.separatorChar));
054        }
055    
056        public int compareTo(RelativePath other) {
057            return path.compareTo(other.path);
058        }
059    
060        @Override
061        public boolean equals(Object other) {
062            if (!(other instanceof RelativePath))
063                return false;
064             return path.equals(((RelativePath) other).path);
065        }
066    
067        @Override
068        public int hashCode() {
069            return path.hashCode();
070        }
071    
072        @Override
073        public String toString() {
074            return "RelPath[" + path + "]";
075        }
076    
077        public String getPath() {
078            return path;
079        }
080    
081        protected final String path;
082    
083        /**
084         * Used to represent a platform-neutral subdirectory within a platform-specific
085         * container, such as a directory or zip file.
086         * Internally, the file separator is always '/', and if the path is not empty,
087         * it always ends in a '/' as well.
088         */
089        public static class RelativeDirectory extends RelativePath {
090    
091            static RelativeDirectory forPackage(CharSequence packageName) {
092                return new RelativeDirectory(packageName.toString().replace('.', '/'));
093            }
094    
095            /**
096             * @param p must use '/' as an internal separator
097             */
098            public RelativeDirectory(String p) {
099                super(p.length() == 0 || p.endsWith("/") ? p : p + "/");
100            }
101    
102            /**
103             * @param p must use '/' as an internal separator
104             */
105            public RelativeDirectory(RelativeDirectory d, String p) {
106                this(d.path + p);
107            }
108    
109            @Override
110            public RelativeDirectory dirname() {
111                int l = path.length();
112                if (l == 0)
113                    return this;
114                int sep = path.lastIndexOf('/', l - 2);
115                return new RelativeDirectory(path.substring(0, sep + 1));
116            }
117    
118            @Override
119            public String basename() {
120                int l = path.length();
121                if (l == 0)
122                    return path;
123                int sep = path.lastIndexOf('/', l - 2);
124                return path.substring(sep + 1, l - 1);
125            }
126    
127            /**
128             * Return true if this subdirectory "contains" the other path.
129             * A subdirectory path does not contain itself.
130             **/
131            boolean contains(RelativePath other) {
132                return other.path.length() > path.length() && other.path.startsWith(path);
133            }
134    
135            @Override
136            public String toString() {
137                return "RelativeDirectory[" + path + "]";
138            }
139        }
140    
141        /**
142         * Used to represent a platform-neutral file within a platform-specific
143         * container, such as a directory or zip file.
144         * Internally, the file separator is always '/'. It never ends in '/'.
145         */
146        public static class RelativeFile extends RelativePath {
147            static RelativeFile forClass(CharSequence className, JavaFileObject.Kind kind) {
148                return new RelativeFile(className.toString().replace('.', '/') + kind.extension);
149            }
150    
151            public RelativeFile(String p) {
152                super(p);
153                if (p.endsWith("/"))
154                    throw new IllegalArgumentException(p);
155            }
156    
157            /**
158             * @param p must use '/' as an internal separator
159             */
160            public RelativeFile(RelativeDirectory d, String p) {
161                this(d.path + p);
162            }
163    
164            RelativeFile(RelativeDirectory d, RelativePath p) {
165                this(d, p.path);
166            }
167    
168            @Override
169            public RelativeDirectory dirname() {
170                int sep = path.lastIndexOf('/');
171                return new RelativeDirectory(path.substring(0, sep + 1));
172            }
173    
174            @Override
175            public String basename() {
176                int sep = path.lastIndexOf('/');
177                return path.substring(sep + 1);
178            }
179    
180            ZipEntry getZipEntry(ZipFile zip) {
181                return zip.getEntry(path);
182            }
183    
184            @Override
185            public String toString() {
186                return "RelativeFile[" + path + "]";
187            }
188    
189        }
190    
191    }