RelativePath.java revision 3155:30e288cb2d22
1/*
2 * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.file;
27
28import java.io.File;
29import java.nio.file.FileSystem;
30import java.nio.file.FileSystems;
31import java.nio.file.InvalidPathException;
32import java.nio.file.Path;
33import java.nio.file.Paths;
34import java.util.zip.ZipEntry;
35import java.util.zip.ZipFile;
36
37import javax.tools.JavaFileObject;
38
39/**
40 * Used to represent a platform-neutral path within a platform-specific
41 * container, such as a directory or zip file.
42 * Internally, the file separator is always '/'.
43 *
44 * <p><b>This is NOT part of any supported API.
45 * If you write code that depends on this, you do so at your own risk.
46 * This code and its internal interfaces are subject to change or
47 * deletion without notice.</b>
48 */
49public abstract class RelativePath implements Comparable<RelativePath> {
50    /**
51     * @param p must use '/' as an internal separator
52     */
53    protected RelativePath(String p) {
54        path = p;
55    }
56
57    public abstract RelativeDirectory dirname();
58
59    public abstract String basename();
60
61    public Path resolveAgainst(Path directory) throws /*unchecked*/ InvalidPathException {
62        if (directory == null) {
63            String sep = FileSystems.getDefault().getSeparator();
64            return Paths.get(path.replace("/", sep));
65        } else {
66            String sep = directory.getFileSystem().getSeparator();
67            return directory.resolve(path.replace("/", sep));
68        }
69    }
70
71    public Path resolveAgainst(FileSystem fs) throws /*unchecked*/ InvalidPathException {
72        String sep = fs.getSeparator();
73        Path root = fs.getRootDirectories().iterator().next();
74        return root.resolve(path.replace("/", sep));
75    }
76
77    @Override
78    public int compareTo(RelativePath other) {
79        return path.compareTo(other.path);
80    }
81
82    @Override
83    public boolean equals(Object other) {
84        if (!(other instanceof RelativePath))
85            return false;
86         return path.equals(((RelativePath) other).path);
87    }
88
89    @Override
90    public int hashCode() {
91        return path.hashCode();
92    }
93
94    @Override
95    public String toString() {
96        return "RelPath[" + path + "]";
97    }
98
99    public String getPath() {
100        return path;
101    }
102
103    protected final String path;
104
105    /**
106     * Used to represent a platform-neutral subdirectory within a platform-specific
107     * container, such as a directory or zip file.
108     * Internally, the file separator is always '/', and if the path is not empty,
109     * it always ends in a '/' as well.
110     */
111    public static class RelativeDirectory extends RelativePath {
112
113        static RelativeDirectory forPackage(CharSequence packageName) {
114            return new RelativeDirectory(packageName.toString().replace('.', '/'));
115        }
116
117        /**
118         * @param p must use '/' as an internal separator
119         */
120        public RelativeDirectory(String p) {
121            super(p.length() == 0 || p.endsWith("/") ? p : p + "/");
122        }
123
124        /**
125         * @param p must use '/' as an internal separator
126         */
127        public RelativeDirectory(RelativeDirectory d, String p) {
128            this(d.path + p);
129        }
130
131        @Override
132        public RelativeDirectory dirname() {
133            int l = path.length();
134            if (l == 0)
135                return this;
136            int sep = path.lastIndexOf('/', l - 2);
137            return new RelativeDirectory(path.substring(0, sep + 1));
138        }
139
140        @Override
141        public String basename() {
142            int l = path.length();
143            if (l == 0)
144                return path;
145            int sep = path.lastIndexOf('/', l - 2);
146            return path.substring(sep + 1, l - 1);
147        }
148
149        /**
150         * Return true if this subdirectory "contains" the other path.
151         * A subdirectory path does not contain itself.
152         **/
153        boolean contains(RelativePath other) {
154            return other.path.length() > path.length() && other.path.startsWith(path);
155        }
156
157        @Override
158        public String toString() {
159            return "RelativeDirectory[" + path + "]";
160        }
161    }
162
163    /**
164     * Used to represent a platform-neutral file within a platform-specific
165     * container, such as a directory or zip file.
166     * Internally, the file separator is always '/'. It never ends in '/'.
167     */
168    public static class RelativeFile extends RelativePath {
169        static RelativeFile forClass(CharSequence className, JavaFileObject.Kind kind) {
170            return new RelativeFile(className.toString().replace('.', '/') + kind.extension);
171        }
172
173        public RelativeFile(String p) {
174            super(p);
175            if (p.endsWith("/"))
176                throw new IllegalArgumentException(p);
177        }
178
179        /**
180         * @param p must use '/' as an internal separator
181         */
182        public RelativeFile(RelativeDirectory d, String p) {
183            this(d.path + p);
184        }
185
186        RelativeFile(RelativeDirectory d, RelativePath p) {
187            this(d, p.path);
188        }
189
190        @Override
191        public RelativeDirectory dirname() {
192            int sep = path.lastIndexOf('/');
193            return new RelativeDirectory(path.substring(0, sep + 1));
194        }
195
196        @Override
197        public String basename() {
198            int sep = path.lastIndexOf('/');
199            return path.substring(sep + 1);
200        }
201
202        ZipEntry getZipEntry(ZipFile zip) {
203            return zip.getEntry(path);
204        }
205
206        @Override
207        public String toString() {
208            return "RelativeFile[" + path + "]";
209        }
210
211    }
212
213}
214