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