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