1 /* 2 * Copyright (c) 2008, 2016, 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 26 package com.sun.tools.javac.file; 27 28 import java.nio.file.FileSystem; 29 import java.nio.file.InvalidPathException; 30 import java.nio.file.Path; 31 import java.util.zip.ZipEntry; 32 import java.util.zip.ZipFile; 33 34 import javax.tools.JavaFileObject; 35 36 /** 37 * Used to represent a platform-neutral path within a platform-specific 38 * container, such as a directory or zip file. 39 * Internally, the file separator is always '/'. 40 * 41 * <p><b>This is NOT part of any supported API. 42 * If you write code that depends on this, you do so at your own risk. 43 * This code and its internal interfaces are subject to change or 44 * deletion without notice.</b> 45 */ 46 public abstract class RelativePath implements Comparable<RelativePath> { 47 /** 48 * @param p must use '/' as an internal separator 49 */ RelativePath(String p)50 protected RelativePath(String p) { 51 path = p; 52 } 53 dirname()54 public abstract RelativeDirectory dirname(); 55 basename()56 public abstract String basename(); 57 resolveAgainst(Path directory)58 public Path resolveAgainst(Path directory) throws /*unchecked*/ InvalidPathException { 59 String sep = directory.getFileSystem().getSeparator(); 60 return directory.resolve(path.replace("/", sep)); 61 } 62 resolveAgainst(FileSystem fs)63 public Path resolveAgainst(FileSystem fs) throws /*unchecked*/ InvalidPathException { 64 String sep = fs.getSeparator(); 65 Path root = fs.getRootDirectories().iterator().next(); 66 return root.resolve(path.replace("/", sep)); 67 } 68 69 @Override compareTo(RelativePath other)70 public int compareTo(RelativePath other) { 71 return path.compareTo(other.path); 72 } 73 74 @Override equals(Object other)75 public boolean equals(Object other) { 76 if (!(other instanceof RelativePath)) 77 return false; 78 return path.equals(((RelativePath) other).path); 79 } 80 81 @Override hashCode()82 public int hashCode() { 83 return path.hashCode(); 84 } 85 86 @Override toString()87 public String toString() { 88 return "RelPath[" + path + "]"; 89 } 90 getPath()91 public String getPath() { 92 return path; 93 } 94 95 protected final String path; 96 97 /** 98 * Used to represent a platform-neutral subdirectory within a platform-specific 99 * container, such as a directory or zip file. 100 * Internally, the file separator is always '/', and if the path is not empty, 101 * it always ends in a '/' as well. 102 */ 103 public static class RelativeDirectory extends RelativePath { 104 forPackage(CharSequence packageName)105 static RelativeDirectory forPackage(CharSequence packageName) { 106 return new RelativeDirectory(packageName.toString().replace('.', '/')); 107 } 108 109 /** 110 * @param p must use '/' as an internal separator 111 */ RelativeDirectory(String p)112 public RelativeDirectory(String p) { 113 super(p.length() == 0 || p.endsWith("/") ? p : p + "/"); 114 } 115 116 /** 117 * @param p must use '/' as an internal separator 118 */ RelativeDirectory(RelativeDirectory d, String p)119 public RelativeDirectory(RelativeDirectory d, String p) { 120 this(d.path + p); 121 } 122 123 @Override dirname()124 public RelativeDirectory dirname() { 125 int l = path.length(); 126 if (l == 0) 127 return this; 128 int sep = path.lastIndexOf('/', l - 2); 129 return new RelativeDirectory(path.substring(0, sep + 1)); 130 } 131 132 @Override basename()133 public String basename() { 134 int l = path.length(); 135 if (l == 0) 136 return path; 137 int sep = path.lastIndexOf('/', l - 2); 138 return path.substring(sep + 1, l - 1); 139 } 140 141 /** 142 * Return true if this subdirectory "contains" the other path. 143 * A subdirectory path does not contain itself. 144 **/ contains(RelativePath other)145 boolean contains(RelativePath other) { 146 return other.path.length() > path.length() && other.path.startsWith(path); 147 } 148 149 @Override toString()150 public String toString() { 151 return "RelativeDirectory[" + path + "]"; 152 } 153 } 154 155 /** 156 * Used to represent a platform-neutral file within a platform-specific 157 * container, such as a directory or zip file. 158 * Internally, the file separator is always '/'. It never ends in '/'. 159 */ 160 public static class RelativeFile extends RelativePath { forClass(CharSequence className, JavaFileObject.Kind kind)161 static RelativeFile forClass(CharSequence className, JavaFileObject.Kind kind) { 162 return new RelativeFile(className.toString().replace('.', '/') + kind.extension); 163 } 164 RelativeFile(String p)165 public RelativeFile(String p) { 166 super(p); 167 if (p.endsWith("/")) 168 throw new IllegalArgumentException(p); 169 } 170 171 /** 172 * @param p must use '/' as an internal separator 173 */ RelativeFile(RelativeDirectory d, String p)174 public RelativeFile(RelativeDirectory d, String p) { 175 this(d.path + p); 176 } 177 RelativeFile(RelativeDirectory d, RelativePath p)178 RelativeFile(RelativeDirectory d, RelativePath p) { 179 this(d, p.path); 180 } 181 182 @Override dirname()183 public RelativeDirectory dirname() { 184 int sep = path.lastIndexOf('/'); 185 return new RelativeDirectory(path.substring(0, sep + 1)); 186 } 187 188 @Override basename()189 public String basename() { 190 int sep = path.lastIndexOf('/'); 191 return path.substring(sep + 1); 192 } 193 getZipEntry(ZipFile zip)194 ZipEntry getZipEntry(ZipFile zip) { 195 return zip.getEntry(path); 196 } 197 198 @Override toString()199 public String toString() { 200 return "RelativeFile[" + path + "]"; 201 } 202 203 } 204 205 } 206