1 11 package org.enhydra.jawe.xml; 13 14 import java.io.File ; 15 16 28 public class Path { 29 32 public static final char SEPARATOR = '/'; 33 34 37 public static final char DEVICE_SEPARATOR = ':'; 38 39 40 private String [] segments; 41 42 43 private String device = null; 44 45 46 private int separators; 47 48 49 private static final int HAS_LEADING = 1; 50 private static final int IS_UNC = 2; 51 private static final int HAS_TRAILING = 4; 52 private static final int ALL_SEPARATORS = HAS_LEADING | IS_UNC | HAS_TRAILING; 53 54 55 private static final int HASH_MASK = ~HAS_TRAILING; 56 57 58 private static final String [] NO_SEGMENTS = new String [0]; 59 60 61 private static final String ROOT_STRING = "/"; 63 64 public static final Path ROOT = new Path(ROOT_STRING); 65 66 67 private static final String EMPTY_STRING = ""; 69 70 public static final Path EMPTY = new Path(EMPTY_STRING); 71 72 private Path(String device, String [] segments, int _separators) { 76 this.segments = segments; 78 this.device = device; 79 this.separators = (computeHashCode() << 3) | (_separators & ALL_SEPARATORS); 81 } 82 83 92 public Path(String fullPath) { 93 initialize(null, fullPath); 95 } 96 97 108 public Path(String device, String path) { 109 initialize(device, path); 111 } 112 113 122 private boolean canonicalize() { 123 for (int i = 0, max = segments.length; i < max; i++) { 125 String segment = segments[i]; 126 if (segment.charAt(0) == '.' && (segment.equals("..") || segment.equals("."))) { collapseParentReferences(); 129 if (segments.length == 0) 131 separators &= (HAS_LEADING | IS_UNC); 132 separators = (separators & ALL_SEPARATORS) | (computeHashCode() << 3); 134 return true; 135 } 136 } 137 return false; 138 } 139 140 143 private void collapseParentReferences() { 144 int segmentCount = segments.length; 145 String [] stack = new String [segmentCount]; 146 int stackPointer = 0; 147 for (int i = 0; i < segmentCount; i++) { 148 String segment = segments[i]; 149 if (segment.equals("..")) { if (stackPointer==0) { 151 if (!isAbsolute()) 156 stack[stackPointer++] = segment; } else { 158 if ("..".equals(stack[stackPointer-1])) stack[stackPointer++] = ".."; else 162 stackPointer--; } 164 } else 166 if (!segment.equals(".") || (i == 0 && !isAbsolute())) stack[stackPointer++] = segment; } 169 if (stackPointer== segmentCount) 171 return; 172 String [] newSegments = new String [stackPointer]; 174 System.arraycopy(stack, 0, newSegments, 0, stackPointer); 175 this.segments = newSegments; 176 } 177 178 182 private String collapseSlashes(String path) { 183 int length = path.length(); 184 if (length < 3) 187 return path; 188 if (path.indexOf("//", 1) == -1) return path; 192 char[] result = new char[path.length()]; 194 int count = 0; 195 boolean hasPrevious = false; 196 char[] characters = path.toCharArray(); 197 for (int index = 0; index < characters.length; index++) { 198 char c = characters[index]; 199 if (c == SEPARATOR) { 200 if (hasPrevious) { 201 if (device == null && index == 1) { 204 result[count] = c; 205 count++; 206 } 207 } else { 208 hasPrevious = true; 209 result[count] = c; 210 count++; 211 } 212 } else { 213 hasPrevious = false; 214 result[count] = c; 215 count++; 216 } 217 } 218 return new String (result, 0, count); 219 } 220 221 224 private int computeHashCode() { 225 int hash = device == null ? 17 : device.hashCode(); 226 int segmentCount = segments.length; 227 for (int i = 0; i < segmentCount; i++) { 228 hash = hash * 37 + segments[i].hashCode(); 230 } 231 return hash; 232 } 233 234 237 private int computeLength() { 238 int length = 0; 239 if (device != null) 240 length += device.length(); 241 if ((separators & HAS_LEADING) != 0) 242 length ++; 243 if ((separators & IS_UNC) != 0) 244 length++; 245 int max = segments.length; 247 if (max > 0) { 248 for (int i = 0; i < max; i++) { 249 length += segments[i].length(); 250 } 251 length += max-1; 253 } 254 if ((separators & HAS_TRAILING) != 0) 255 length++; 256 return length; 257 } 258 259 262 private int computeSegmentCount(String path) { 263 int len = path.length(); 264 if (len == 0 || (len == 1 && path.charAt(0) == SEPARATOR)) { 265 return 0; 266 } 267 int count = 1; 268 int prev = -1; 269 int i; 270 while ((i = path.indexOf(SEPARATOR, prev + 1)) != -1) { 271 if (i != prev + 1 && i != len) { 272 ++count; 273 } 274 prev = i; 275 } 276 if (path.charAt(len - 1) == SEPARATOR) { 277 --count; 278 } 279 return count; 280 } 281 282 285 private String [] computeSegments(String path) { 286 int segmentCount = computeSegmentCount(path); 288 if (segmentCount == 0) 289 return NO_SEGMENTS; 290 String [] newSegments = new String [segmentCount]; 291 int len = path.length(); 292 int firstPosition = (path.charAt(0) == SEPARATOR) ? 1 : 0; 294 if (firstPosition == 1 && len > 1 && (path.charAt(1) == SEPARATOR)) 296 firstPosition = 2; 297 int lastPosition = (path.charAt(len - 1) != SEPARATOR) ? len - 1 : len - 2; 298 int next = firstPosition; 302 for (int i = 0; i < segmentCount; i++) { 303 int start = next; 304 int end = path.indexOf(SEPARATOR, next); 305 if (end == -1) { 306 newSegments[i] = path.substring(start, lastPosition + 1); 307 } else { 308 newSegments[i] = path.substring(start, end); 309 } 310 next = end + 1; 311 } 312 return newSegments; 313 } 314 315 316 319 private void initialize(String device, String fullPath) { 320 if (fullPath==null) throw new RuntimeException (); 321 this.device = device; 322 323 String path = fullPath.indexOf('\\') == -1 ? fullPath : fullPath.replace('\\', SEPARATOR); 325 326 int i = path.indexOf(DEVICE_SEPARATOR); 327 if (i != -1) { 328 if (device == null) 331 this.device = path.substring(0, i + 1); 332 path = path.substring(i + 1, path.length()); 333 } 334 path = collapseSlashes(path); 335 int len = path.length(); 336 337 if (len < 2) { 339 if (len == 1 && path.charAt(0) == SEPARATOR) { 340 this.separators = HAS_LEADING; 341 } else { 342 this.separators = 0; 343 } 344 } else { 345 boolean hasLeading = path.charAt(0) == SEPARATOR; 346 boolean isUNC = hasLeading && path.charAt(1) == SEPARATOR; 347 boolean hasTrailing = !(isUNC && len == 2) && path.charAt(len-1) == SEPARATOR; 349 separators = hasLeading ? HAS_LEADING : 0; 350 if (isUNC) separators |= IS_UNC; 351 if (hasTrailing) separators |= HAS_TRAILING; 352 } 353 segments = computeSegments(path); 355 if (!canonicalize()) { 356 separators = (separators & ALL_SEPARATORS) | (computeHashCode() << 3); 358 } 359 } 360 361 public boolean isAbsolute() { 362 return (separators & HAS_LEADING) != 0; 364 } 365 366 public int matchingFirstSegments(Path anotherPath) { 367 if (anotherPath==null) throw new RuntimeException (); 368 int anotherPathLen = anotherPath.segmentCount(); 369 int max = Math.min(segments.length, anotherPathLen); 370 int count = 0; 371 for (int i = 0; i < max; i++) { 372 if (!segments[i].equals(anotherPath.segment(i))) { 373 return count; 374 } 375 count++; 376 } 377 return count; 378 } 379 380 public String segment(int index) { 381 if (index >= segments.length) 382 return null; 383 return segments[index]; 384 } 385 386 public int segmentCount() { 387 return segments.length; 388 } 389 390 public String [] segments() { 391 String [] segmentCopy = new String [segments.length]; 392 System.arraycopy(segments, 0, segmentCopy, 0, segments.length); 393 return segmentCopy; 394 } 395 396 public Path setDevice(String value) { 397 if (value != null) { 398 if (value.indexOf(Path.DEVICE_SEPARATOR) != (value.length() - 1)) throw new RuntimeException ("Last character should be the device separator"); 400 } 401 if (value == device || (value != null && value.equals(device))) 403 return this; 404 405 return new Path(value, segments, separators); 406 } 407 408 public String toOSString() { 409 int resultSize = computeLength(); 412 if (resultSize <= 0) 413 return EMPTY_STRING; 414 char FILE_SEPARATOR = File.separatorChar; 415 char[] result = new char[resultSize]; 416 int offset = 0; 417 if (device != null) { 418 int size = device.length(); 419 device.getChars(0, size, result, offset); 420 offset += size; 421 } 422 if ((separators & HAS_LEADING) != 0) 423 result[offset++] = FILE_SEPARATOR; 424 if ((separators & IS_UNC) != 0) 425 result[offset++] = FILE_SEPARATOR; 426 int len = segments.length-1; 427 if (len>=0) { 428 for (int i = 0; i < len; i++) { 430 int size = segments[i].length(); 431 segments[i].getChars(0, size, result, offset); 432 offset += size; 433 result[offset++] = FILE_SEPARATOR; 434 } 435 int size = segments[len].length(); 437 segments[len].getChars(0, size, result, offset); 438 offset += size; 439 } 440 if ((separators & HAS_TRAILING) != 0) 441 result[offset++] = FILE_SEPARATOR; 442 return new String (result); 443 } 444 445 public static String getRelativePath(Path fullPath,Path fBasePath) { 446 if (fBasePath == null || !hasSameDevice(fullPath, fBasePath)) { 447 return fullPath.toOSString(); 448 } 449 int matchingSegments= fBasePath.matchingFirstSegments(fullPath); 450 StringBuffer res= new StringBuffer (); 451 int backSegments= fBasePath.segmentCount() - matchingSegments; 452 while (backSegments > 0) { 453 res.append(".."); res.append(File.separatorChar); 455 backSegments--; 456 } 457 int segCount= fullPath.segmentCount(); 458 for (int i= matchingSegments; i < segCount; i++) { 459 if (i > matchingSegments) { 460 res.append(File.separatorChar); 461 } 462 res.append(fullPath.segment(i)); 463 } 464 return res.toString(); 465 } 466 467 private static boolean hasSameDevice(Path p1, Path p2) { 468 String dev= p1.device; 469 if (dev == null) { 470 return p2.device == null; 471 } 472 return dev.equals(p2.device); 473 } 474 475 } 476 | Popular Tags |