001 /* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 package org.crsh.vfs; 021 022 import org.crsh.util.BaseIterator; 023 024 import java.util.Iterator; 025 import java.util.NoSuchElementException; 026 027 public abstract class Path implements Iterable<String> { 028 029 /** . */ 030 private static final String[] EMPTY_STRING = new String[0]; 031 032 /** . */ 033 public static final Absolute ROOT = new Absolute(true, EMPTY_STRING); 034 035 /** . */ 036 public static final Relative EMPTY = new Relative(true, EMPTY_STRING); 037 038 private static String[] path(java.io.File file, int size) { 039 String[] ret; 040 java.io.File parent = file.getParentFile(); 041 if (parent != null && parent.isDirectory()) { 042 ret = path(parent, 1 + size); 043 } else { 044 ret = new String[1 + size]; 045 } 046 ret[ret.length - size - 1] = file.getName(); 047 return ret; 048 } 049 050 public static Path get(java.io.File file) { 051 String[] names = path(file, 0); 052 if (file.isAbsolute()) { 053 return new Absolute(file.isDirectory(), names); 054 } else { 055 return new Relative(file.isDirectory(), names); 056 } 057 } 058 059 public static Path get(String s) { 060 if (s.length() == 0) { 061 return EMPTY; 062 } 063 064 // 065 int start; 066 boolean absolute; 067 if (s.charAt(0) != '/') { 068 start = 0; 069 absolute = false; 070 } else { 071 if (s.length() == 1) { 072 return ROOT; 073 } else { 074 start = 1; 075 absolute = true; 076 } 077 } 078 079 // 080 boolean dir; 081 int end; 082 if (s.charAt(s.length() - 1) == '/') { 083 dir = true; 084 end = s.length() - 1; 085 } else { 086 dir = false; 087 end = s.length(); 088 } 089 090 // 091 String[] names = parseNames(s, start, end, 0); 092 093 // 094 return absolute ? new Absolute(dir, names) : new Relative(dir, names); 095 } 096 097 private static String[] parseNames(final String s, final int prev, int end, final int count) { 098 int next = s.indexOf('/', prev); 099 if (next == -1 || next > end) { 100 if (prev < end) { 101 String[] ret = new String[count + 1]; 102 ret[count] = s.substring(prev); 103 return ret; 104 } else { 105 return new String[count]; 106 } 107 } else if (next - prev > 0) { 108 String[] ret = parseNames(s, next + 1, end, count + 1); 109 ret[count] = s.substring(prev, next); 110 return ret; 111 } else { 112 return parseNames(s, next + 1, end, count); 113 } 114 } 115 116 /** . */ 117 protected final boolean dir; 118 119 /** . */ 120 protected final String[] names; 121 122 /** . */ 123 private String value; 124 125 private Path(boolean dir, String[] names) { 126 this.dir = dir; 127 this.names = names; 128 } 129 130 public Iterator<String> iterator() { 131 return new BaseIterator<String>() { 132 int index = 0; 133 public boolean hasNext() { 134 return index < names.length; 135 } 136 public String next() { 137 if (index < names.length) { 138 return names[index++]; 139 } else { 140 throw new NoSuchElementException(); 141 } 142 } 143 }; 144 } 145 146 public Path append(String name, boolean dir) { 147 int length = names.length; 148 String[] names = new String[length + 1]; 149 System.arraycopy(names, 0, names, 0, length); 150 names[length] = name; 151 return create(dir, names); 152 } 153 154 protected abstract Path create(boolean dir, String[] names); 155 156 public abstract boolean isAbsolute(); 157 158 public abstract Absolute absolute(); 159 160 public int getSize() { 161 return names.length; 162 } 163 164 public boolean isDir() { 165 return dir; 166 } 167 168 public String getName() { 169 return names.length > 0 ? names[names.length - 1] : ""; 170 } 171 172 public String nameAt(int index) throws IndexOutOfBoundsException { 173 if (index < 0 || index >= names.length) { 174 throw new IndexOutOfBoundsException("Index out of bounds [0" + (names.length - 1) + "]" + index); 175 } else { 176 return names[index]; 177 } 178 } 179 180 public boolean isChildOf(Path parent) { 181 if (parent.dir) { 182 int length = parent.names.length; 183 if (names.length == length + 1) { 184 for (int i = 0;i < length;i++) { 185 if (names[i].equals(parent.names[i])) { 186 return false; 187 } 188 } 189 return true; 190 } 191 } 192 return false; 193 } 194 195 @Override 196 public boolean equals(Object o) { 197 if (o == this) { 198 return true; 199 } 200 if (o instanceof Path) { 201 Path that = (Path)o; 202 int length = that.names.length; 203 if (names.length == length) { 204 for (int i = 0;i < length;i++) { 205 if (!names[i].equals(that.names[i])) { 206 return false; 207 } 208 } 209 return true; 210 } 211 } 212 return false; 213 } 214 215 @Override 216 public int hashCode() { 217 int hashCode = dir ? 1 : 0; 218 for (int i = names.length - 1;i >= 0;i--) { 219 hashCode = hashCode * 41 + names[i].hashCode(); 220 } 221 return hashCode; 222 } 223 224 /** 225 * Returns the canonical path value. 226 * 227 * @return the value 228 */ 229 public String getValue() { 230 if (value == null) { 231 if (names.length == 0) { 232 if (isAbsolute()) { 233 return "/"; 234 } else { 235 return ""; 236 } 237 } else { 238 StringBuilder sb = new StringBuilder(8 * names.length); 239 if (isAbsolute()) { 240 sb.append('/'); 241 } 242 for (int i = 0;i < names.length;i++) { 243 if (i > 0) { 244 sb.append('/'); 245 } 246 sb.append(names[i]); 247 } 248 if (dir) { 249 sb.append('/'); 250 } 251 value = sb.toString(); 252 } 253 } 254 return value; 255 } 256 257 public String toString() { 258 return "Path[value=" + getValue() + "]"; 259 } 260 261 public static class Absolute extends Path { 262 263 private Absolute(boolean dir, String[] names) { 264 super(dir, names); 265 } 266 267 @Override 268 public Absolute append(String name, boolean dir) { 269 return (Absolute)super.append(name, dir); 270 } 271 272 @Override 273 protected Absolute create(boolean dir, String[] names) { 274 return new Absolute(dir, names); 275 } 276 277 @Override 278 public Absolute absolute() { 279 return this; 280 } 281 282 @Override 283 public boolean isAbsolute() { 284 return true; 285 } 286 } 287 288 public static class Relative extends Path { 289 290 private Relative(boolean dir, String[] names) { 291 super(dir, names); 292 } 293 294 @Override 295 public Relative append(String name, boolean dir) { 296 return (Relative)super.append(name, dir); 297 } 298 299 @Override 300 protected Relative create(boolean dir, String[] names) { 301 return new Relative(dir, names); 302 } 303 304 @Override 305 public Absolute absolute() { 306 return new Absolute(dir, names); 307 } 308 309 @Override 310 public boolean isAbsolute() { 311 return false; 312 } 313 } 314 }