1 11 package org.eclipse.core.runtime; 12 13 import java.io.File ; 14 15 31 public class Path implements IPath, Cloneable { 32 33 private static final int HAS_LEADING = 1; 34 private static final int IS_UNC = 2; 35 private static final int HAS_TRAILING = 4; 36 37 private static final int ALL_SEPARATORS = HAS_LEADING | IS_UNC | HAS_TRAILING; 38 39 40 private static final String EMPTY_STRING = ""; 42 43 private static final String [] NO_SEGMENTS = new String [0]; 44 45 46 public static final Path EMPTY = new Path(EMPTY_STRING); 47 48 49 private static final int HASH_MASK = ~HAS_TRAILING; 50 51 52 53 private static final String ROOT_STRING = "/"; 55 56 public static final Path ROOT = new Path(ROOT_STRING); 57 58 59 private static final boolean WINDOWS = java.io.File.separatorChar == '\\'; 60 61 62 private String device = null; 63 64 68 69 private String [] segments; 70 71 72 private int separators; 73 74 88 public static IPath fromOSString(String pathString) { 89 return new Path(pathString); 90 } 91 92 101 public static IPath fromPortableString(String pathString) { 102 int firstMatch = pathString.indexOf(DEVICE_SEPARATOR) +1; 103 if (firstMatch <= 0) 105 return new Path().initialize(null, pathString); 106 String devicePart = null; 108 int pathLength = pathString.length(); 109 if (firstMatch == pathLength || pathString.charAt(firstMatch) != DEVICE_SEPARATOR) { 110 devicePart = pathString.substring(0, firstMatch); 111 pathString = pathString.substring(firstMatch, pathLength); 112 } 113 if (pathString.indexOf(DEVICE_SEPARATOR) == -1) 115 return new Path().initialize(devicePart, pathString); 116 char[] chars = pathString.toCharArray(); 118 int readOffset = 0, writeOffset = 0, length = chars.length; 119 while (readOffset < length) { 120 if (chars[readOffset] == DEVICE_SEPARATOR) 121 if (++readOffset >= length) 122 break; 123 chars[writeOffset++] = chars[readOffset++]; 124 } 125 return new Path().initialize(devicePart, new String (chars, 0, writeOffset)); 126 } 127 128 131 private Path() { 132 } 134 135 148 public Path(String fullPath) { 149 String devicePart = null; 150 if (WINDOWS) { 151 fullPath = fullPath.indexOf('\\') == -1 ? fullPath : fullPath.replace('\\', SEPARATOR); 153 int i = fullPath.indexOf(DEVICE_SEPARATOR); 155 if (i != -1) { 156 int start = fullPath.charAt(0) == SEPARATOR ? 1 : 0; 158 devicePart = fullPath.substring(start, i + 1); 159 fullPath = fullPath.substring(i + 1, fullPath.length()); 160 } 161 } 162 initialize(devicePart, fullPath); 163 } 164 165 179 public Path(String device, String path) { 180 if (WINDOWS) { 181 path = path.indexOf('\\') == -1 ? path : path.replace('\\', SEPARATOR); 183 } 184 initialize(device, path); 185 } 186 187 190 private Path(String device, String [] segments, int _separators) { 191 this.segments = segments; 193 this.device = device; 194 this.separators = (computeHashCode() << 3) | (_separators & ALL_SEPARATORS); 196 } 197 198 201 public IPath addFileExtension(String extension) { 202 if (isRoot() || isEmpty() || hasTrailingSeparator()) 203 return this; 204 int len = segments.length; 205 String [] newSegments = new String [len]; 206 System.arraycopy(segments, 0, newSegments, 0, len - 1); 207 newSegments[len - 1] = segments[len - 1] + '.' + extension; 208 return new Path(device, newSegments, separators); 209 } 210 211 214 public IPath addTrailingSeparator() { 215 if (hasTrailingSeparator() || isRoot()) { 216 return this; 217 } 218 if (isEmpty()) { 220 return new Path(device, segments, HAS_LEADING); 221 } 222 return new Path(device, segments, separators | HAS_TRAILING); 223 } 224 225 228 public IPath append(IPath tail) { 229 if (tail == null || tail.segmentCount() == 0) 231 return this; 232 if (this.isEmpty()) 234 return tail.setDevice(device).makeRelative().makeUNC(isUNC()); 235 if (this.isRoot()) 236 return tail.setDevice(device).makeAbsolute().makeUNC(isUNC()); 237 238 int myLen = segments.length; 240 int tailLen = tail.segmentCount(); 241 String [] newSegments = new String [myLen + tailLen]; 242 System.arraycopy(segments, 0, newSegments, 0, myLen); 243 for (int i = 0; i < tailLen; i++) { 244 newSegments[myLen + i] = tail.segment(i); 245 } 246 Path result = new Path(device, newSegments, (separators & (HAS_LEADING | IS_UNC)) | (tail.hasTrailingSeparator() ? HAS_TRAILING : 0)); 248 String tailFirstSegment = newSegments[myLen]; 249 if (tailFirstSegment.equals("..") || tailFirstSegment.equals(".")) { result.canonicalize(); 251 } 252 return result; 253 } 254 255 258 public IPath append(String tail) { 259 if (tail.indexOf(SEPARATOR) == -1 && tail.indexOf("\\") == -1 && tail.indexOf(DEVICE_SEPARATOR) == -1) { int tailLength = tail.length(); 262 if (tailLength < 3) { 263 if (tailLength == 0 || ".".equals(tail)) { return this; 266 } 267 if ("..".equals(tail)) return removeLastSegments(1); 269 } 270 int myLen = segments.length; 272 String [] newSegments = new String [myLen + 1]; 273 System.arraycopy(segments, 0, newSegments, 0, myLen); 274 newSegments[myLen] = tail; 275 return new Path(device, newSegments, separators & ~HAS_TRAILING); 276 } 277 return append(new Path(tail)); 279 } 280 281 290 private boolean canonicalize() { 291 for (int i = 0, max = segments.length; i < max; i++) { 293 String segment = segments[i]; 294 if (segment.charAt(0) == '.' && (segment.equals("..") || segment.equals("."))) { collapseParentReferences(); 297 if (segments.length == 0) 299 separators &= (HAS_LEADING | IS_UNC); 300 separators = (separators & ALL_SEPARATORS) | (computeHashCode() << 3); 302 return true; 303 } 304 } 305 return false; 306 } 307 308 311 public Object clone() { 312 try { 313 return super.clone(); 314 } catch (CloneNotSupportedException e) { 315 return null; 316 } 317 } 318 319 322 private void collapseParentReferences() { 323 int segmentCount = segments.length; 324 String [] stack = new String [segmentCount]; 325 int stackPointer = 0; 326 for (int i = 0; i < segmentCount; i++) { 327 String segment = segments[i]; 328 if (segment.equals("..")) { if (stackPointer == 0) { 330 if (!isAbsolute()) 335 stack[stackPointer++] = segment; } else { 337 if ("..".equals(stack[stackPointer - 1])) stack[stackPointer++] = ".."; else 341 stackPointer--; 342 } 344 } else if (!segment.equals(".") || segmentCount == 1) stack[stackPointer++] = segment; } 348 if (stackPointer == segmentCount) 350 return; 351 String [] newSegments = new String [stackPointer]; 353 System.arraycopy(stack, 0, newSegments, 0, stackPointer); 354 this.segments = newSegments; 355 } 356 357 361 private String collapseSlashes(String path) { 362 int length = path.length(); 363 if (length < 3) 366 return path; 367 if (path.indexOf("//", 1) == -1) return path; 371 char[] result = new char[path.length()]; 373 int count = 0; 374 boolean hasPrevious = false; 375 char[] characters = path.toCharArray(); 376 for (int index = 0; index < characters.length; index++) { 377 char c = characters[index]; 378 if (c == SEPARATOR) { 379 if (hasPrevious) { 380 if (device == null && index == 1) { 383 result[count] = c; 384 count++; 385 } 386 } else { 387 hasPrevious = true; 388 result[count] = c; 389 count++; 390 } 391 } else { 392 hasPrevious = false; 393 result[count] = c; 394 count++; 395 } 396 } 397 return new String (result, 0, count); 398 } 399 400 403 private int computeHashCode() { 404 int hash = device == null ? 17 : device.hashCode(); 405 int segmentCount = segments.length; 406 for (int i = 0; i < segmentCount; i++) { 407 hash = hash * 37 + segments[i].hashCode(); 409 } 410 return hash; 411 } 412 413 416 private int computeLength() { 417 int length = 0; 418 if (device != null) 419 length += device.length(); 420 if ((separators & HAS_LEADING) != 0) 421 length++; 422 if ((separators & IS_UNC) != 0) 423 length++; 424 int max = segments.length; 426 if (max > 0) { 427 for (int i = 0; i < max; i++) { 428 length += segments[i].length(); 429 } 430 length += max - 1; 432 } 433 if ((separators & HAS_TRAILING) != 0) 434 length++; 435 return length; 436 } 437 438 441 private int computeSegmentCount(String path) { 442 int len = path.length(); 443 if (len == 0 || (len == 1 && path.charAt(0) == SEPARATOR)) { 444 return 0; 445 } 446 int count = 1; 447 int prev = -1; 448 int i; 449 while ((i = path.indexOf(SEPARATOR, prev + 1)) != -1) { 450 if (i != prev + 1 && i != len) { 451 ++count; 452 } 453 prev = i; 454 } 455 if (path.charAt(len - 1) == SEPARATOR) { 456 --count; 457 } 458 return count; 459 } 460 461 464 private String [] computeSegments(String path) { 465 int segmentCount = computeSegmentCount(path); 467 if (segmentCount == 0) 468 return NO_SEGMENTS; 469 String [] newSegments = new String [segmentCount]; 470 int len = path.length(); 471 int firstPosition = (path.charAt(0) == SEPARATOR) ? 1 : 0; 473 if (firstPosition == 1 && len > 1 && (path.charAt(1) == SEPARATOR)) 475 firstPosition = 2; 476 int lastPosition = (path.charAt(len - 1) != SEPARATOR) ? len - 1 : len - 2; 477 int next = firstPosition; 481 for (int i = 0; i < segmentCount; i++) { 482 int start = next; 483 int end = path.indexOf(SEPARATOR, next); 484 if (end == -1) { 485 newSegments[i] = path.substring(start, lastPosition + 1); 486 } else { 487 newSegments[i] = path.substring(start, end); 488 } 489 next = end + 1; 490 } 491 return newSegments; 492 } 493 497 private void encodeSegment(String string, StringBuffer buf) { 498 int len = string.length(); 499 for (int i = 0; i < len; i++) { 500 char c = string.charAt(i); 501 buf.append(c); 502 if (c == DEVICE_SEPARATOR) 503 buf.append(DEVICE_SEPARATOR); 504 } 505 } 506 507 510 public boolean equals(Object obj) { 511 if (this == obj) 512 return true; 513 if (!(obj instanceof Path)) 514 return false; 515 Path target = (Path) obj; 516 if ((separators & HASH_MASK) != (target.separators & HASH_MASK)) 518 return false; 519 String [] targetSegments = target.segments; 520 int i = segments.length; 521 if (i != targetSegments.length) 523 return false; 524 while (--i >= 0) 526 if (!segments[i].equals(targetSegments[i])) 527 return false; 528 return device == target.device || (device != null && device.equals(target.device)); 530 } 531 532 535 public String getDevice() { 536 return device; 537 } 538 539 542 public String getFileExtension() { 543 if (hasTrailingSeparator()) { 544 return null; 545 } 546 String lastSegment = lastSegment(); 547 if (lastSegment == null) { 548 return null; 549 } 550 int index = lastSegment.lastIndexOf('.'); 551 if (index == -1) { 552 return null; 553 } 554 return lastSegment.substring(index + 1); 555 } 556 557 560 public int hashCode() { 561 return separators & HASH_MASK; 562 } 563 564 567 public boolean hasTrailingSeparator() { 568 return (separators & HAS_TRAILING) != 0; 569 } 570 571 574 private IPath initialize(String deviceString, String path) { 575 Assert.isNotNull(path); 576 this.device = deviceString; 577 578 path = collapseSlashes(path); 579 int len = path.length(); 580 581 if (len < 2) { 583 if (len == 1 && path.charAt(0) == SEPARATOR) { 584 this.separators = HAS_LEADING; 585 } else { 586 this.separators = 0; 587 } 588 } else { 589 boolean hasLeading = path.charAt(0) == SEPARATOR; 590 boolean isUNC = hasLeading && path.charAt(1) == SEPARATOR; 591 boolean hasTrailing = !(isUNC && len == 2) && path.charAt(len - 1) == SEPARATOR; 593 separators = hasLeading ? HAS_LEADING : 0; 594 if (isUNC) 595 separators |= IS_UNC; 596 if (hasTrailing) 597 separators |= HAS_TRAILING; 598 } 599 segments = computeSegments(path); 601 if (!canonicalize()) { 602 separators = (separators & ALL_SEPARATORS) | (computeHashCode() << 3); 604 } 605 return this; 606 } 607 608 611 public boolean isAbsolute() { 612 return (separators & HAS_LEADING) != 0; 614 } 615 616 619 public boolean isEmpty() { 620 return segments.length == 0 && ((separators & ALL_SEPARATORS) != HAS_LEADING); 622 623 } 624 625 628 public boolean isPrefixOf(IPath anotherPath) { 629 if (device == null) { 630 if (anotherPath.getDevice() != null) { 631 return false; 632 } 633 } else { 634 if (!device.equalsIgnoreCase(anotherPath.getDevice())) { 635 return false; 636 } 637 } 638 if (isEmpty() || (isRoot() && anotherPath.isAbsolute())) { 639 return true; 640 } 641 int len = segments.length; 642 if (len > anotherPath.segmentCount()) { 643 return false; 644 } 645 for (int i = 0; i < len; i++) { 646 if (!segments[i].equals(anotherPath.segment(i))) 647 return false; 648 } 649 return true; 650 } 651 652 655 public boolean isRoot() { 656 return this == ROOT || (segments.length == 0 && ((separators & ALL_SEPARATORS) == HAS_LEADING)); 658 } 659 660 663 public boolean isUNC() { 664 if (device != null) 665 return false; 666 return (separators & IS_UNC) != 0; 667 } 668 669 672 public boolean isValidPath(String path) { 673 Path test = new Path(path); 674 for (int i = 0, max = test.segmentCount(); i < max; i++) 675 if (!isValidSegment(test.segment(i))) 676 return false; 677 return true; 678 } 679 680 683 public boolean isValidSegment(String segment) { 684 int size = segment.length(); 685 if (size == 0) 686 return false; 687 for (int i = 0; i < size; i++) { 688 char c = segment.charAt(i); 689 if (c == '/') 690 return false; 691 if (WINDOWS && (c == '\\' || c == ':')) 692 return false; 693 } 694 return true; 695 } 696 697 700 public String lastSegment() { 701 int len = segments.length; 702 return len == 0 ? null : segments[len - 1]; 703 } 704 705 708 public IPath makeAbsolute() { 709 if (isAbsolute()) { 710 return this; 711 } 712 Path result = new Path(device, segments, separators | HAS_LEADING); 713 if (result.segmentCount() > 0) { 715 String first = result.segment(0); 716 if (first.equals("..") || first.equals(".")) { result.canonicalize(); 718 } 719 } 720 return result; 721 } 722 723 726 public IPath makeRelative() { 727 if (!isAbsolute()) { 728 return this; 729 } 730 return new Path(device, segments, separators & HAS_TRAILING); 731 } 732 733 736 public IPath makeUNC(boolean toUNC) { 737 if (!(toUNC ^ isUNC())) 739 return this; 740 741 int newSeparators = this.separators; 742 if (toUNC) { 743 newSeparators |= HAS_LEADING | IS_UNC; 744 } else { 745 newSeparators &= HAS_LEADING | HAS_TRAILING; 747 } 748 return new Path(toUNC ? null : device, segments, newSeparators); 749 } 750 751 754 public int matchingFirstSegments(IPath anotherPath) { 755 Assert.isNotNull(anotherPath); 756 int anotherPathLen = anotherPath.segmentCount(); 757 int max = Math.min(segments.length, anotherPathLen); 758 int count = 0; 759 for (int i = 0; i < max; i++) { 760 if (!segments[i].equals(anotherPath.segment(i))) { 761 return count; 762 } 763 count++; 764 } 765 return count; 766 } 767 768 771 public IPath removeFileExtension() { 772 String extension = getFileExtension(); 773 if (extension == null || extension.equals("")) { return this; 775 } 776 String lastSegment = lastSegment(); 777 int index = lastSegment.lastIndexOf(extension) - 1; 778 return removeLastSegments(1).append(lastSegment.substring(0, index)); 779 } 780 781 784 public IPath removeFirstSegments(int count) { 785 if (count == 0) 786 return this; 787 if (count >= segments.length) { 788 return new Path(device, NO_SEGMENTS, 0); 789 } 790 Assert.isLegal(count > 0); 791 int newSize = segments.length - count; 792 String [] newSegments = new String [newSize]; 793 System.arraycopy(this.segments, count, newSegments, 0, newSize); 794 795 return new Path(device, newSegments, separators & HAS_TRAILING); 797 } 798 799 802 public IPath removeLastSegments(int count) { 803 if (count == 0) 804 return this; 805 if (count >= segments.length) { 806 return new Path(device, NO_SEGMENTS, separators & (HAS_LEADING | IS_UNC)); 808 } 809 Assert.isLegal(count > 0); 810 int newSize = segments.length - count; 811 String [] newSegments = new String [newSize]; 812 System.arraycopy(this.segments, 0, newSegments, 0, newSize); 813 return new Path(device, newSegments, separators); 814 } 815 816 819 public IPath removeTrailingSeparator() { 820 if (!hasTrailingSeparator()) { 821 return this; 822 } 823 return new Path(device, segments, separators & (HAS_LEADING | IS_UNC)); 824 } 825 826 829 public String segment(int index) { 830 if (index >= segments.length) 831 return null; 832 return segments[index]; 833 } 834 835 838 public int segmentCount() { 839 return segments.length; 840 } 841 842 845 public String [] segments() { 846 String [] segmentCopy = new String [segments.length]; 847 System.arraycopy(segments, 0, segmentCopy, 0, segments.length); 848 return segmentCopy; 849 } 850 851 854 public IPath setDevice(String value) { 855 if (value != null) { 856 Assert.isTrue(value.indexOf(IPath.DEVICE_SEPARATOR) == (value.length() - 1), "Last character should be the device separator"); } 858 if (value == device || (value != null && value.equals(device))) 860 return this; 861 862 return new Path(value, segments, separators); 863 } 864 865 868 public File toFile() { 869 return new File (toOSString()); 870 } 871 872 875 public String toOSString() { 876 int resultSize = computeLength(); 879 if (resultSize <= 0) 880 return EMPTY_STRING; 881 char FILE_SEPARATOR = File.separatorChar; 882 char[] result = new char[resultSize]; 883 int offset = 0; 884 if (device != null) { 885 int size = device.length(); 886 device.getChars(0, size, result, offset); 887 offset += size; 888 } 889 if ((separators & HAS_LEADING) != 0) 890 result[offset++] = FILE_SEPARATOR; 891 if ((separators & IS_UNC) != 0) 892 result[offset++] = FILE_SEPARATOR; 893 int len = segments.length - 1; 894 if (len >= 0) { 895 for (int i = 0; i < len; i++) { 897 int size = segments[i].length(); 898 segments[i].getChars(0, size, result, offset); 899 offset += size; 900 result[offset++] = FILE_SEPARATOR; 901 } 902 int size = segments[len].length(); 904 segments[len].getChars(0, size, result, offset); 905 offset += size; 906 } 907 if ((separators & HAS_TRAILING) != 0) 908 result[offset++] = FILE_SEPARATOR; 909 return new String (result); 910 } 911 912 915 public String toPortableString() { 916 int resultSize = computeLength(); 917 if (resultSize <= 0) 918 return EMPTY_STRING; 919 StringBuffer result = new StringBuffer (resultSize); 920 if (device != null) 921 result.append(device); 922 if ((separators & HAS_LEADING) != 0) 923 result.append(SEPARATOR); 924 if ((separators & IS_UNC) != 0) 925 result.append(SEPARATOR); 926 int len = segments.length; 927 for (int i = 0; i < len; i++) { 929 if (segments[i].indexOf(DEVICE_SEPARATOR) >= 0) 930 encodeSegment(segments[i], result); 931 else 932 result.append(segments[i]); 933 if (i < len-1 || (separators & HAS_TRAILING) != 0) 934 result.append(SEPARATOR); 935 } 936 return result.toString(); 937 } 938 939 942 public String toString() { 943 int resultSize = computeLength(); 944 if (resultSize <= 0) 945 return EMPTY_STRING; 946 char[] result = new char[resultSize]; 947 int offset = 0; 948 if (device != null) { 949 int size = device.length(); 950 device.getChars(0, size, result, offset); 951 offset += size; 952 } 953 if ((separators & HAS_LEADING) != 0) 954 result[offset++] = SEPARATOR; 955 if ((separators & IS_UNC) != 0) 956 result[offset++] = SEPARATOR; 957 int len = segments.length - 1; 958 if (len >= 0) { 959 for (int i = 0; i < len; i++) { 961 int size = segments[i].length(); 962 segments[i].getChars(0, size, result, offset); 963 offset += size; 964 result[offset++] = SEPARATOR; 965 } 966 int size = segments[len].length(); 968 segments[len].getChars(0, size, result, offset); 969 offset += size; 970 } 971 if ((separators & HAS_TRAILING) != 0) 972 result[offset++] = SEPARATOR; 973 return new String (result); 974 } 975 976 979 public IPath uptoSegment(int count) { 980 if (count == 0) 981 return new Path(device, NO_SEGMENTS, separators & (HAS_LEADING | IS_UNC)); 982 if (count >= segments.length) 983 return this; 984 Assert.isTrue(count > 0, "Invalid parameter to Path.uptoSegment"); String [] newSegments = new String [count]; 986 System.arraycopy(segments, 0, newSegments, 0, count); 987 return new Path(device, newSegments, separators); 988 } 989 } | Popular Tags |