1 6 21 22 package de.schlichtherle.io; 23 24 import de.schlichtherle.io.ArchiveController.ArchiveNotFoundException; 25 import de.schlichtherle.io.util.*; 26 27 import java.io.*; 28 import java.lang.ref.*; 29 import java.lang.reflect.*; 30 import java.lang.reflect.Proxy ; 31 import java.net.*; 32 import java.util.*; 33 34 import javax.swing.Icon ; 35 36 328 public class File extends java.io.File implements FileConstants, Cloneable { 329 330 331 private static final HashSet roots = new HashSet(Arrays.asList(listRoots())); 332 333 334 private static final String uncPrefix = separator + separator; 335 336 private static final Executor readerExecutor 337 = getExecutor("TrueZIP InputStream Reader"); 338 339 343 private static boolean lenient = true; 344 345 private static ArchiveDetector defaultDetector = ArchiveDetector.DEFAULT; 346 347 367 private final java.io.File delegate; 368 369 372 private final ArchiveDetector detector; 373 374 379 private File innerArchive; 380 381 386 private String innerEntryName; 387 388 393 private File enclArchive; 394 395 400 private String enclEntryName; 401 402 407 private transient ArchiveController controller; 409 413 public File(java.io.File blueprint) { 414 this(blueprint, defaultDetector); 415 } 416 417 428 public File( 429 final java.io.File blueprint, 430 final ArchiveDetector detector) { 431 super(blueprint.getPath()); 432 433 if (blueprint instanceof File) { 434 final File file = (File) blueprint; 435 this.delegate = file.delegate; 436 this.detector = file.detector; 437 this.enclArchive = file.enclArchive; 438 this.enclEntryName = file.enclEntryName; 439 this.innerArchive = file.isArchive() ? this : file.innerArchive; 440 this.innerEntryName = file.innerEntryName; 441 this.controller = file.controller; 442 } else { 443 this.delegate = blueprint; 444 this.detector = detector; 445 init((File) null); 446 } 447 448 assert invariants(true); 449 } 450 451 455 public File(String pathName) { 456 this(pathName, defaultDetector); 457 } 458 459 468 public File( 469 final String pathName, 470 final ArchiveDetector detector) { 471 super(pathName); 472 473 delegate = new java.io.File (pathName); 474 this.detector = detector; 475 init((File) null); 476 477 assert invariants(true); 478 } 479 480 484 public File(String parent, String child) { 485 this(parent, child, defaultDetector); 486 } 487 488 498 public File( 499 final String parent, 500 final String child, 501 final ArchiveDetector detector) { 502 super(parent, child); 503 504 delegate = new java.io.File (parent, child); 505 this.detector = detector; 506 init((File) null); 507 508 assert invariants(true); 509 } 510 511 525 public File(java.io.File parent, String child) { 526 this(parent, child, null); 527 } 528 529 546 public File( 547 final java.io.File parent, 548 final String child, 549 final ArchiveDetector detector) { 550 super(parent, child); 551 552 delegate = new java.io.File (parent, child); 553 if (parent instanceof File) { 554 final File smartParent = (File) parent; 555 this.detector = detector != null ? detector : smartParent.detector; 556 init(smartParent); 557 } else { 558 this.detector = detector != null ? detector : defaultDetector; 559 init((File) null); 560 } 561 562 assert invariants(true); 563 } 564 565 598 public File(URI uri) { 599 this(uri, ArchiveDetector.ALL); 600 } 601 602 File( 606 final URI uri, 607 final ArchiveDetector detector) { 608 super(unjarFileURI(uri)); 609 610 delegate = new java.io.File (super.getPath()); 611 this.detector = detector; 612 init(uri); 613 614 assert invariants(true); 615 } 616 617 621 private static final URI unjarFileURI(final URI uri) { 622 try { 623 final String scheme = uri.getScheme(); 624 final String ssp = Paths.normalize(uri.getSchemeSpecificPart(), '/'); 625 return unjarFileURIImpl(new URI(scheme, ssp, null)); 626 } catch (URISyntaxException ignored) { 627 } 630 throw new IllegalArgumentException (uri + ": Not a valid (possibly jared) file URI!"); 631 } 632 633 private static final URI unjarFileURIImpl(final URI uri) 634 throws URISyntaxException { 635 final String scheme = uri.getScheme(); 636 if ("jar".equalsIgnoreCase(scheme)) { 637 final String rssp = uri.getRawSchemeSpecificPart(); 638 final int i; 639 if (rssp.endsWith("!")) 640 i = rssp.length() - 1; 641 else 642 i = rssp.lastIndexOf("!/"); 643 644 if (i <= 0) 645 return unjarFileURI(new URI(rssp)); 647 final URI subURI = new URI( 648 rssp.substring(0, i) + rssp.substring(i + 1)); final String subScheme = subURI.getScheme(); 650 if ("jar".equalsIgnoreCase(subScheme)) { 651 final URI processedSubURI = unjarFileURIImpl(subURI); 652 if (processedSubURI != subURI) 653 return processedSubURI; 654 } else if ("file".equalsIgnoreCase(subScheme)) { 656 return subURI; } 658 } else if ("file".equalsIgnoreCase(scheme)) { 659 return uri; 660 } 661 throw new URISyntaxException(uri.toString(), "Not a valid (possibly jared) file URI!"); 662 } 663 664 669 public File( 670 final java.io.File delegate, 671 final File innerArchive, 672 final ArchiveDetector detector) { 673 super(delegate.getPath()); 674 675 assert assertParams(delegate, innerArchive, detector); 676 677 this.delegate = delegate; 678 679 final String path = delegate.getPath(); 680 if (innerArchive != null) { 681 final int innerArchivePathLength 682 = innerArchive.getPath().length(); 683 if (path.length() == innerArchivePathLength) { 684 this.detector = innerArchive.detector; 685 this.innerArchive = this; 686 this.innerEntryName = EMPTY; 687 this.enclArchive = innerArchive.enclArchive; 688 this.enclEntryName = innerArchive.enclEntryName; 689 this.controller = ArchiveController.getInstance(this); 690 } else { 691 this.detector = detector; 692 this.innerArchive = this.enclArchive = innerArchive; 693 this.innerEntryName = this.enclEntryName 694 = path.substring(innerArchivePathLength + 1) .replace(separatorChar, ENTRY_SEPARATOR_CHAR); 696 } 697 } else { 698 this.detector = detector; 699 } 700 701 assert invariants(true); 702 } 703 704 708 private static final boolean assertParams( 709 final java.io.File delegate, 710 final File innerArchive, 711 final ArchiveDetector detector) 712 throws AssertionError { 713 assert delegate != null : "delegate is null!"; 714 assert !(delegate instanceof File) : "delegate must not be a de.schlichtherle.io.File!"; 715 if (innerArchive != null) { 716 assert innerArchive.isArchive() : "innerArchive must be an archive!"; 717 assert containsImpl(innerArchive, delegate) 718 : "innerArchive must contain delegate!"; 719 } 720 assert detector != null : "detector is null!"; 721 722 return true; 723 } 724 725 730 public File( 731 final File blueprint, 732 final java.io.File delegate, 733 final File enclArchive) { 734 super(delegate.getPath()); 735 736 assert parameters(blueprint, delegate, enclArchive); 737 738 this.delegate = delegate; 739 this.detector = blueprint.detector; 740 this.enclArchive = enclArchive; 741 this.enclEntryName = blueprint.enclEntryName; 742 this.innerArchive = blueprint.isArchive() ? this : enclArchive; 743 this.innerEntryName = blueprint.innerEntryName; 744 this.controller = blueprint.controller; 745 746 assert invariants(blueprint.controller != null); 747 } 748 749 757 private void init(final File ancestor) { 758 final String path = super.getPath(); 759 assert ancestor == null || path.startsWith(ancestor.getPath()); 760 assert delegate.getPath().equals(path); 761 assert detector != null; 762 763 final StringBuffer enclEntryNameBuf = new StringBuffer (path.length()); 764 init(ancestor, detector, 0, path, enclEntryNameBuf, new String [2]); 765 enclEntryName = enclEntryNameBuf.length() > 0 ? enclEntryNameBuf.toString() : null; 766 767 if (innerArchive == this) { 768 innerEntryName = EMPTY; 772 controller = ArchiveController.getInstance(this); 773 } else if (innerArchive == enclArchive) { 774 innerEntryName = enclEntryName; 775 } 776 } 777 778 private void init( 779 File ancestor, 780 ArchiveDetector detector, 781 int skip, 782 final String path, 783 final StringBuffer enclEntryNameBuf, 784 final String [] split) { 785 if (path == null) { 786 assert enclArchive == null; 787 enclEntryNameBuf.setLength(0); 788 return; 789 } 790 791 Paths.split(path, separatorChar, split); 792 final String parent = split[0]; 793 final String base = split[1]; 794 795 if (base.length() == 0 || ".".equals(base)) { 796 } else if ("..".equals(base)) { 798 skip++; 799 } else if (skip > 0) { 800 skip--; 801 } else { 802 if (ancestor != null) { 803 final int pathLen = path.length(); 804 final int ancestorPathLen = ancestor.getPath().length(); 805 if (pathLen == ancestorPathLen) { 806 enclArchive = ancestor.innerArchive; 813 if (!ancestor.isArchive()) { 814 if (ancestor.isEntry()) { 815 if (enclEntryNameBuf.length() > 0) { 816 enclEntryNameBuf.insert(0, '/'); 817 enclEntryNameBuf.insert(0, ancestor.enclEntryName); 818 } else { assert enclArchive == ancestor.enclArchive; 822 enclEntryNameBuf.append(ancestor.enclEntryName); 823 } 824 } else { 825 assert enclArchive == null; 826 enclEntryNameBuf.setLength(0); 827 } 828 } else if (enclEntryNameBuf.length() <= 0) { assert enclArchive == ancestor; 832 innerArchive = this; 833 enclArchive = ancestor.enclArchive; 834 if (ancestor.enclEntryName != null) 835 enclEntryNameBuf.append(ancestor.enclEntryName); 836 } 837 if (innerArchive != this) 838 innerArchive = enclArchive; 839 return; 840 } else if (pathLen < ancestorPathLen) { 841 detector = ancestor.detector; 842 ancestor = ancestor.enclArchive; 843 } 844 } 845 846 final boolean isArchive = detector.getArchiveDriver(path) != null; 847 if (enclEntryNameBuf.length() > 0) { 848 if (isArchive) { 849 enclArchive = detector.createFile(path); if (innerArchive != this) 851 innerArchive = enclArchive; 852 return; 853 } 854 enclEntryNameBuf.insert(0, '/'); 855 enclEntryNameBuf.insert(0, base); 856 } else { 857 if (isArchive) 858 innerArchive = this; 859 enclEntryNameBuf.append(base); 860 } 861 } 862 863 init(ancestor, detector, skip, parent, enclEntryNameBuf, split); 864 } 865 866 873 private void init(final URI uri) { 874 assert uri != null; 875 assert delegate.getPath().equals(super.getPath()); 876 assert detector != null; 877 878 init(uri, 0, Paths.cutTrailingSeparators( 879 uri.getSchemeSpecificPart(), '/')); 880 881 if (innerArchive == this) { 882 controller = ArchiveController.getInstance(this); 886 } 887 } 888 889 893 private void init( 894 URI uri, 895 int skip, 896 final String path) { 897 String scheme = uri.getScheme(); 898 if (path == null || !"jar".equalsIgnoreCase(scheme)) { 899 assert enclArchive == null; 900 enclEntryName = null; 901 return; 902 } 903 904 final String [] split = Paths.split(path, '/'); 905 String parent = split[0]; 906 final String base = split[1]; 908 if (base.length() == 0 || ".".equals(base)) { 909 } else if ("..".equals(base)) { 911 skip++; 912 } else if (skip > 0) { 913 skip--; 914 } else { 915 final int baseEnd = base.length() - 1; 916 final boolean isArchive = base.charAt(baseEnd) == '!'; 917 if (enclEntryName != null) { 918 if (isArchive) { 919 enclArchive = detector.createFile(createURI(scheme, path)); if (innerArchive != this) { 921 innerArchive = enclArchive; 922 innerEntryName = enclEntryName; 923 } 924 return; 925 } 926 enclEntryName = base + "/" + enclEntryName; 927 } else { 928 if (isArchive) { 929 innerArchive = this; 930 innerEntryName = EMPTY; 931 int i = parent.indexOf(':'); 932 assert i >= 0; 933 scheme = parent.substring(0, i); 934 assert scheme.matches("[a-zA-Z]+"); 935 if (i == parent.length() - 1) return; 937 uri = createURI(parent.substring(0, i), parent.substring(i + 1)); 938 enclEntryName = base.substring(0, baseEnd); parent = uri.getSchemeSpecificPart(); 940 } else { 941 enclEntryName = base; 942 } 943 } 944 } 945 946 init(uri, skip, parent); 947 } 948 949 954 private URI createURI(String scheme, String ssp) 955 throws IllegalArgumentException { 956 try { 957 return new URI(scheme, ssp, null); 958 } catch (URISyntaxException syntaxError) { 959 IllegalArgumentException iae = new IllegalArgumentException (syntaxError.toString()); 960 iae.initCause(syntaxError); 961 throw iae; 962 } 963 } 964 965 971 private static boolean parameters( 972 final File blueprint, 973 final java.io.File delegate, 974 final File enclArchive) 975 throws AssertionError { 976 assert delegate != null : "delegate is null!"; 977 assert !(delegate instanceof File) 978 : "delegate must not be a de.schlichtherle.io.File!"; 979 assert blueprint != null : "blueprint is null!"; 980 981 String delegatePath = delegate.getPath(); 982 final java.io.File normalizedBlueprint = normalize(blueprint); 983 String normalizedBlueprintPath = normalizedBlueprint.getPath(); 984 String normalizedBlueprintBase = normalizedBlueprint.getName(); 985 if (separatorChar != '/') { 992 delegatePath = delegatePath.toLowerCase(); 993 normalizedBlueprintPath = normalizedBlueprintPath.toLowerCase(); 994 normalizedBlueprintBase = normalizedBlueprintBase.toLowerCase(); 995 } 996 if (!".".equals(normalizedBlueprintBase) 997 && !"..".equals(normalizedBlueprintBase) 998 && !normalizedBlueprintPath.startsWith("." + separator) 999 && !normalizedBlueprintPath.startsWith(".." + separator)) { 1000 assert delegatePath.endsWith(normalizedBlueprintPath) 1001 : "delegate and blueprint must identify the same directory!"; 1002 if (enclArchive != null) { 1003 assert enclArchive.isArchive() 1004 : "enclArchive must be an archive file!"; 1005 assert containsImpl(enclArchive, delegate.getParentFile()) 1006 : "enclArchive must be an ancestor of delegate!"; 1007 } 1008 } 1009 1010 return true; 1011 } 1012 1013 private void readObject(final ObjectInputStream in) 1014 throws IOException, ClassNotFoundException { 1015 in.defaultReadObject(); 1016 if (innerArchive == this) { 1017 assert EMPTY.equals(innerEntryName); assert EMPTY != innerEntryName; assert controller == null; innerEntryName = EMPTY; controller = ArchiveController.getInstance(this); } 1023 assert invariants(true); 1024 } 1025 1026 1032 private boolean invariants(final boolean controllerInit) 1033 throws AssertionError { 1034 assert delegate != null; 1035 assert !(delegate instanceof File); 1036 assert delegate.getPath().equals(super.getPath()); 1037 assert detector != null; 1038 assert (innerArchive != null) == (innerEntryName != null); 1039 assert (enclArchive != null) == (enclEntryName != null); 1040 assert (innerArchive == this 1041 && innerArchive != enclArchive 1042 && innerEntryName == EMPTY 1043 && innerEntryName != enclEntryName 1044 && (controllerInit 1045 ? controller != null 1046 : controller == null)) 1047 ^ (innerArchive == enclArchive 1048 && innerEntryName == enclEntryName 1049 && controller == null); 1050 assert enclArchive == null 1051 || containsImpl(enclArchive, delegate.getParentFile()) 1052 && enclEntryName.length() > 0 1053 && (separatorChar == '/' 1054 || enclEntryName.indexOf(separatorChar) == -1); 1055 1056 return true; 1057 } 1058 1059 1071 static java.io.File normalize(java.io.File file) { 1072 final String possiblyDotifiedPath = file.getPath(); 1073 final String path = Paths.normalize(possiblyDotifiedPath, separatorChar); 1074 if (path != possiblyDotifiedPath) return new java.io.File (path); 1076 else 1077 return file; 1078 } 1079 1080 1084 public static final void umount() 1085 throws ArchiveException { 1086 ArchiveController.updateAll("", false, true, false, true, true, true); 1087 } 1088 1089 1093 public static final void umount(boolean closeStreams) 1094 throws ArchiveException { 1095 ArchiveController.updateAll("", 1096 false, closeStreams, 1097 false, closeStreams, 1098 true, true); 1099 } 1100 1101 1321 public static final void umount( 1322 boolean waitInputStreams, boolean closeInputStreams, 1323 boolean waitOutputStreams, boolean closeOutputStreams) 1324 throws ArchiveException { 1325 ArchiveController.updateAll("", 1326 waitInputStreams, closeInputStreams, 1327 waitOutputStreams, closeOutputStreams, 1328 true, true); 1329 } 1330 1331 1335 public static final void umount(File archive) 1336 throws ArchiveException { 1337 umount(archive, false, true, false, true); 1338 } 1339 1340 1344 public static final void umount(File archive, boolean closeStreams) 1345 throws ArchiveException { 1346 umount(archive, false, closeStreams, false, closeStreams); 1347 } 1348 1349 1364 public static final void umount( 1365 File archive, 1366 boolean waitInputStreams, boolean closeInputStreams, 1367 boolean waitOutputStreams, boolean closeOutputStreams) 1368 throws ArchiveException { 1369 if (!archive.isArchive()) 1370 throw new IllegalArgumentException (archive.getPath() + " (not an archive)"); 1371 if (archive.getEnclArchive() != null) 1372 throw new IllegalArgumentException (archive.getPath() + " (not a top level archive)"); 1373 ArchiveController.updateAll(archive.getCanOrAbsPath(), 1374 waitInputStreams, closeInputStreams, 1375 waitOutputStreams, closeOutputStreams, 1376 true, true); 1377 } 1378 1379 1383 public static final void update() 1384 throws ArchiveException { 1385 ArchiveController.updateAll("", 1386 false, true, 1387 false, true, 1388 false, true); 1389 } 1390 1391 1395 public static final void update(boolean closeStreams) 1396 throws ArchiveException { 1397 ArchiveController.updateAll("", 1398 false, closeStreams, 1399 false, closeStreams, 1400 false, true); 1401 } 1402 1403 1420 public static final void update( 1421 boolean waitInputStreams, boolean closeInputStreams, 1422 boolean waitOutputStreams, boolean closeOutputStreams) 1423 throws ArchiveException { 1424 ArchiveController.updateAll("", 1425 waitInputStreams, closeInputStreams, 1426 waitOutputStreams, closeOutputStreams, 1427 false, true); 1428 } 1429 1430 1434 public static final void update(File archive) 1435 throws ArchiveException { 1436 update(archive, false, true, false, true); 1437 } 1438 1439 1443 public static final void update(File archive, boolean closeStreams) 1444 throws ArchiveException { 1445 update(archive, false, closeStreams, false, closeStreams); 1446 } 1447 1448 1463 public static final void update( 1464 File archive, 1465 boolean waitInputStreams, boolean closeInputStreams, 1466 boolean waitOutputStreams, boolean closeOutputStreams) 1467 throws ArchiveException { 1468 if (!archive.isArchive()) 1469 throw new IllegalArgumentException (archive.getPath() + " (not an archive)"); 1470 if (archive.getEnclArchive() != null) 1471 throw new IllegalArgumentException (archive.getPath() + " (not a top level archive)"); 1472 ArchiveController.updateAll(archive.getCanOrAbsPath(), 1473 waitInputStreams, closeInputStreams, 1474 waitOutputStreams, closeOutputStreams, 1475 false, true); 1476 } 1477 1478 1493 public static final ArchiveStatistics getLiveArchiveStatistics() { 1494 return ArchiveController.getLiveStatistics(); 1495 } 1496 1497 1588 public static final void setLenient(final boolean lenient) { 1589 File.lenient = lenient; 1590 } 1591 1592 1593 public static final boolean isLenient() { 1594 return lenient; 1595 } 1596 1597 1615 public static final void setDefaultArchiveDetector(final ArchiveDetector detector) { 1616 if (detector == null) 1617 throw new NullPointerException (); 1618 File.defaultDetector = detector; 1619 } 1620 1621 1633 public static final ArchiveDetector getDefaultArchiveDetector() { 1634 return defaultDetector; 1635 } 1636 1637 1642 public Object clone() { 1643 return detector.createFile(this); 1644 } 1645 1646 1651 public java.io.File getParentFile() { 1652 final java.io.File parent = delegate.getParentFile(); 1653 if (parent == null) 1654 return null; 1655 1656 assert super.getName().equals(delegate.getName()); 1657 if (enclArchive != null 1658 && enclArchive.getPath().length() == parent.getPath().length()) { 1659 assert enclArchive.getPath().equals(parent.getPath()); 1660 return enclArchive; 1661 } 1662 1663 return detector.createFile(parent, enclArchive); 1669 } 1670 1671 1675 public File getNonArchivedParentFile() { 1676 final File enclArchive = this.enclArchive; 1677 return enclArchive != null 1678 ? enclArchive.getNonArchivedParentFile() 1679 : (File) getParentFile(); 1680 } 1681 1682 1689 public java.io.File getAbsoluteFile() { 1690 File enclArchive = this.enclArchive; 1691 if (enclArchive != null) 1692 enclArchive = (File) enclArchive.getAbsoluteFile(); 1693 return detector.createFile(this, delegate.getAbsoluteFile(), enclArchive); 1694 } 1695 1696 1706 public File getNormalizedAbsoluteFile() { 1707 File enclArchive = this.enclArchive; 1708 if (enclArchive != null) 1709 enclArchive = enclArchive.getNormalizedAbsoluteFile(); 1710 return detector.createFile(this, normalize(delegate.getAbsoluteFile()), enclArchive); 1711 } 1712 1713 1721 public String getNormalizedAbsolutePath() { 1722 return Paths.normalize(getAbsolutePath(), separatorChar); 1723 } 1724 1725 1732 public File getNormalizedFile() { 1733 final java.io.File normalizedFile = normalize(this); 1734 if (normalizedFile == this) 1735 return this; 1736 assert normalizedFile != null; 1737 assert !(normalizedFile instanceof File); 1738 assert normalize(enclArchive) == enclArchive; 1739 return detector.createFile(this, normalizedFile, enclArchive); 1740 } 1741 1742 1750 public String getNormalizedPath() { 1751 return Paths.normalize(getPath(), separatorChar); 1752 } 1753 1754 1761 public java.io.File getCanonicalFile() throws IOException { 1762 File enclArchive = this.enclArchive; 1763 if (enclArchive != null) 1764 enclArchive = (File) enclArchive.getCanonicalFile(); 1765 return detector.createFile(this, delegate.getCanonicalFile(), enclArchive); 1767 } 1768 1769 1777 public final File getCanOrAbsFile() { 1778 File enclArchive = this.enclArchive; 1779 if (enclArchive != null) 1780 enclArchive = enclArchive.getCanOrAbsFile(); 1781 return detector.createFile(this, getCanOrAbsFile(delegate), enclArchive); 1782 } 1783 1784 private static java.io.File getCanOrAbsFile(java.io.File file) { 1785 try { 1786 return file.getCanonicalFile(); 1787 } catch (IOException failure) { 1788 final java.io.File parent = file.getParentFile(); 1789 return normalize(parent != null 1790 ? new java.io.File (getCanOrAbsFile(parent), file.getName()) 1791 : file.getAbsoluteFile()); 1792 } 1793 } 1794 1795 1805 public String getCanOrAbsPath() { 1806 return getCanOrAbsFile().getPath(); 1807 } 1808 1809 1829 public final boolean isArchive() { 1830 return innerArchive == this; 1831 } 1832 1833 1852 public final boolean isEntry() { 1853 return enclEntryName != null; 1854 } 1855 1856 1872 public final File getInnerArchive() { 1873 return innerArchive; 1874 } 1875 1876 1890 public final String getInnerEntryName() { 1891 return innerEntryName; 1892 } 1893 1894 1908 public final File getEnclArchive() { 1909 return enclArchive; 1910 } 1911 1912 1923 public final String getEnclEntryName() { 1924 return enclEntryName; 1925 } 1926 1927 1931 public final ArchiveDetector getArchiveDetector() { 1932 return detector; 1933 } 1934 1935 1954 public final java.io.File getDelegate() { 1955 return delegate; 1956 } 1957 1958 1962 final ArchiveController getArchiveController() { 1963 return controller; 1964 } 1965 1966 1985 public boolean isParentOf(java.io.File file) { 1986 File canOrAbsFile = getCanOrAbsFile(); 1988 try { 1989 return containsImpl(canOrAbsFile, file.getCanonicalFile().getParentFile()); 1990 } catch (IOException exc) { 1991 return containsImpl(canOrAbsFile, normalize(file.getAbsoluteFile()).getParentFile()); 1992 } 1993 } 1994 1995 2018 public boolean contains(java.io.File file) { 2019 return contains(this, file); 2020 } 2021 2022 2043 public static boolean contains(java.io.File a, java.io.File b) { 2044 a = getCanOrAbsFile(a); 2045 b = getCanOrAbsFile(b); 2046 return containsImpl(a, b); 2047 } 2048 2049 private static boolean containsImpl( 2050 final java.io.File a, 2051 final java.io.File b) { 2052 if (b == null) 2053 return false; 2054 2055 String aPath = a.getPath(); 2056 String bPath = b.getPath(); 2057 if (separatorChar != '/') { 2064 aPath = aPath.toLowerCase(); 2065 bPath = bPath.toLowerCase(); 2066 } 2067 2068 if (!bPath.startsWith(aPath)) 2069 return false; 2070 final int aLength = aPath.length(); 2071 final int bLength = bPath.length(); 2072 if (aLength == bLength) 2073 return true; 2074 else if (aLength < bLength) 2075 return bPath.charAt(aLength) == separatorChar; 2076 else 2077 return false; 2078 2079 2083 } 2084 2085 2089 public boolean isFileSystemRoot() { 2090 File canOrAbsFile = getCanOrAbsFile(); 2091 return roots.contains(canOrAbsFile) || isUNC(canOrAbsFile.getPath()); 2092 } 2093 2094 2098 public boolean isUNC() { 2099 return isUNC(getCanOrAbsFile().getPath()); 2100 } 2101 2102 2109 protected static final boolean isUNC(final String path) { 2110 return path.startsWith(uncPrefix) && path.indexOf(separatorChar, 2) > 2; 2111 } 2112 2113 public int hashCode() { 2114 final File enclArchive = this.enclArchive; 2124 if (enclArchive != null) { 2125 return enclArchive.hashCode() + enclEntryName.hashCode(); 2127 } else { 2128 return delegate.hashCode(); 2130 } 2131 } 2132 2133 2208 public boolean equals(final Object other) { 2209 if (other instanceof File) 2210 return compareTo((File) other) == 0; 2211 return super.equals(other); } 2213 2214 2242 public int compareTo(java.io.File other) { 2243 if (this == other) 2244 return 0; 2245 2246 if (!(other instanceof File)) { 2247 return super.compareTo(other); } 2251 2252 final File file = (File) other; 2253 2254 final File enclArchive = this.enclArchive; 2261 if (enclArchive != null) { 2262 final File fileEnclArchive = file.enclArchive; 2264 if (fileEnclArchive != null) { 2265 int ret = enclArchive.compareTo(fileEnclArchive); 2267 if (ret == 0) { 2268 ret = enclEntryName.compareTo(file.enclEntryName); 2271 } 2272 2273 return ret; 2274 } 2275 } 2276 2277 return super.compareTo(other); } 2281 2282 2290 public File getTopLevelArchive() { 2291 final File enclArchive = this.enclArchive; 2292 return enclArchive != null 2293 ? enclArchive.getTopLevelArchive() 2294 : innerArchive; 2295 } 2296 2297 public String getAbsolutePath() { 2298 return delegate.getAbsolutePath(); 2299 } 2300 2301 public String getCanonicalPath() throws IOException { 2302 return delegate.getCanonicalPath(); 2303 } 2304 2305 public String getName() { 2306 return delegate.getName(); 2307 } 2308 2309 public String getParent() { 2310 return delegate.getParent(); 2311 } 2312 2313 public String getPath() { 2314 return delegate.getPath(); 2315 } 2316 2317 public boolean isAbsolute() { 2318 return delegate.isAbsolute(); 2319 } 2320 2321 public boolean isHidden() { 2322 return delegate.isHidden(); 2323 } 2324 2325 public String toString() { 2326 return delegate.toString(); 2327 } 2328 2329 public java.net.URI toURI() { 2330 return delegate.toURI(); 2331 } 2332 2333 public java.net.URL toURL() throws java.net.MalformedURLException { 2334 return delegate.toURL(); 2335 } 2336 2337 2343 final void ensureNotVirtualDirectory(final String prefix) 2344 throws ArchiveNotFoundException { 2345 if (isArchive() && (isDirectory() || (exists() && !isFile()))) { 2346 String msg = "virtual directory"; 2347 if (prefix != null) 2348 msg = prefix + " " + msg; 2349 throw getArchiveController().new ArchiveNotFoundException(msg); 2350 } 2351 } 2352 2353 2357 2363 public boolean exists() { 2364 if (enclArchive == null) 2365 return delegate.exists(); 2366 try { 2367 return enclArchive.getArchiveController().exists(enclEntryName); 2368 } catch (ArchiveController.FalsePositiveNativeException failure) { 2369 return delegate.exists(); 2370 } 2371 } 2372 2373 2382 public boolean isFile() { 2383 if (innerArchive == null) 2384 return delegate.isFile(); 2385 try { 2386 return innerArchive.getArchiveController().isFile(innerEntryName); 2387 } catch (ArchiveController.FalsePositiveNativeException failure) { 2388 if (isArchive() 2389 && failure.getCause() instanceof FileNotFoundException) { 2390 return false; 2402 } else { 2403 return delegate.isFile(); 2404 } 2405 } 2406 } 2407 2408 2425 public boolean isDirectory() { 2426 if (innerArchive == null) 2427 return delegate.isDirectory(); 2428 try { 2429 return innerArchive.getArchiveController().isDirectory(innerEntryName); 2430 } catch (ArchiveController.FalsePositiveNativeException failure) { 2431 return delegate.isDirectory(); 2432 } 2433 } 2434 2435 2440 public Icon getOpenIcon() { 2441 if (innerArchive == null) 2442 return null; 2443 try { 2444 return innerArchive.getArchiveController().getOpenIcon(innerEntryName); 2445 } catch (ArchiveController.FalsePositiveNativeException failure) { 2446 return null; 2447 } 2448 } 2449 2450 2455 public Icon getClosedIcon() { 2456 if (innerArchive == null) 2457 return null; 2458 try { 2459 return innerArchive.getArchiveController().getClosedIcon(innerEntryName); 2460 } catch (ArchiveController.FalsePositiveNativeException failure) { 2461 return null; 2462 } 2463 } 2464 2465 public boolean canRead() { 2466 if (innerArchive == null) 2468 return delegate.canRead(); 2469 try { 2470 return innerArchive.getArchiveController().canRead(innerEntryName); 2471 } catch (ArchiveController.FalsePositiveNativeException failure) { 2472 return delegate.canRead(); 2473 } 2474 } 2475 2476 public boolean canWrite() { 2477 if (innerArchive == null) 2478 return delegate.canWrite(); 2479 try { 2480 return innerArchive.getArchiveController().canWrite(innerEntryName); 2481 } catch (ArchiveController.FalsePositiveNativeException failure) { 2482 return delegate.canWrite(); 2483 } 2484 } 2485 2486 2499 static boolean isWritableOrCreatable(final java.io.File file) { 2500 try { 2501 if (!file.exists()) { 2502 final boolean created = file.createNewFile(); 2503 boolean ok = isWritableOrCreatable(file); 2504 if (created && !file.delete()) 2505 ok = false; return ok; 2507 } else if (file.canWrite()) { 2508 final long time = file.lastModified(); 2512 if (!file.setLastModified(time + 1)) { 2513 return false; 2518 } 2519 2520 boolean ok; 2521 try { 2522 final RandomAccessFile raf = new RandomAccessFile(file, "rwd"); 2534 try { 2535 final boolean empty; 2536 int octet = raf.read(); 2537 if (octet == -1) { 2538 octet = 0; empty = true; 2540 } else { 2541 empty = false; 2542 } 2543 2544 raf.seek(0); 2546 raf.write((octet ^ -1) & 0xFF); try { 2548 raf.seek(0); 2550 raf.write(octet); 2551 raf.seek(0); 2552 final int check = raf.read(); 2553 ok = octet == check; 2556 } finally { 2557 if (empty) 2558 raf.setLength(0); 2559 } 2560 } finally { 2561 raf.close(); 2562 } 2563 } finally { 2564 if (!file.setLastModified(time)) { 2565 ok = false; 2571 } 2572 } 2573 return ok; 2574 } else { return false; 2576 } 2577 } catch (IOException failure) { 2578 return false; } 2580 } 2581 2582 2591 public boolean setReadOnly() { 2592 if (innerArchive == null) 2593 return delegate.setReadOnly(); 2594 try { 2595 return innerArchive.getArchiveController().setReadOnly(innerEntryName); 2596 } catch (ArchiveController.FalsePositiveNativeException failure) { 2597 return delegate.setReadOnly(); 2598 } 2599 } 2600 2601 2619 public long length() { 2620 if (innerArchive == null) 2621 return delegate.length(); 2622 try { 2623 return innerArchive.getArchiveController().length(innerEntryName); 2624 } catch (ArchiveController.FalsePositiveNativeException failure) { 2625 return delegate.length(); 2626 } 2627 } 2628 2629 2641 public long lastModified() { 2642 if (innerArchive == null) 2643 return delegate.lastModified(); 2644 try { 2645 return innerArchive.getArchiveController().lastModified(innerEntryName); 2646 } catch (ArchiveController.FalsePositiveNativeException failure) { 2647 return delegate.lastModified(); 2648 } 2649 } 2650 2651 2667 public boolean setLastModified(final long time) { 2668 if (innerArchive == null) 2669 return delegate.setLastModified(time); 2670 try { 2671 return innerArchive.getArchiveController().setLastModified( 2672 innerEntryName, time); 2673 } catch (ArchiveController.FalsePositiveNativeException failure) { 2674 return delegate.setLastModified(time); 2675 } 2676 } 2677 2678 2689 public String [] list() { 2690 if (innerArchive == null) 2691 return delegate.list(); 2692 try { 2693 return innerArchive.getArchiveController().list(innerEntryName); 2694 } catch (ArchiveController.FalsePositiveNativeException failure) { 2695 return delegate.list(); 2696 } 2697 } 2698 2699 2712 public String [] list(final FilenameFilter filenameFilter) { 2713 if (innerArchive == null) 2714 return delegate.list(filenameFilter); 2715 try { 2716 return innerArchive.getArchiveController().list( 2717 innerEntryName, 2718 filenameFilter, 2719 this); 2720 } catch (ArchiveController.FalsePositiveNativeException failure) { 2721 return delegate.list(filenameFilter); 2722 } 2723 } 2724 2725 2729 public java.io.File [] listFiles() { 2730 return listFiles((FilenameFilter) null, detector); 2731 } 2732 2733 2754 public File[] listFiles(final FileFactory factory) { 2755 return listFiles((FilenameFilter) null, factory); 2756 } 2757 2758 2762 public java.io.File [] listFiles(final FilenameFilter filenameFilter) { 2763 return listFiles(filenameFilter, detector); 2764 } 2765 2766 2788 public File[] listFiles( 2789 final FilenameFilter filenameFilter, 2790 final FileFactory factory) { 2791 if (innerArchive == null) 2792 return convert(delegate.listFiles(filenameFilter), factory); 2793 try { 2794 return innerArchive.getArchiveController().listFiles( 2795 innerEntryName, filenameFilter, this, factory); 2796 } catch (ArchiveController.FalsePositiveNativeException failure) { 2797 return convert(delegate.listFiles(filenameFilter), factory); 2798 } 2799 } 2800 2801 private static File[] convert( 2802 final java.io.File [] files, 2803 final FileFactory factory) { 2804 if (files == null) 2805 return null; 2806 2807 File[] results = new File[files.length]; 2808 for (int i = files.length; 0 <= --i; ) 2809 results[i] = factory.createFile(files[i]); 2810 2811 return results; 2812 } 2813 2814 2818 public final java.io.File [] listFiles(final FileFilter fileFilter) { 2819 return listFiles(fileFilter, detector); 2820 } 2821 2822 2843 public File[] listFiles( 2844 final FileFilter fileFilter, 2845 final FileFactory factory) { 2846 if (innerArchive == null) 2847 return delegateListFiles(fileFilter, factory); 2848 try { 2849 return innerArchive.getArchiveController().listFiles( 2850 innerEntryName, fileFilter, this, factory); 2851 } catch (ArchiveController.FalsePositiveNativeException failure) { 2852 return delegateListFiles(fileFilter, factory); 2853 } 2854 } 2855 2856 private File[] delegateListFiles( 2857 final FileFilter fileFilter, 2858 final FileFactory factory) { 2859 2867 final List filteredList = new ArrayList(); 2868 final String [] children = delegate.list(); 2869 if (children == null) 2870 return null; 2871 2872 for (int i = 0, l = children.length; i < l; i++) { 2873 final String child = children[i]; 2874 final File file = factory.createFile(this, child); 2875 if (fileFilter == null || fileFilter.accept(file)) 2876 filteredList.add(file); 2877 } 2878 final File[] list = new File[filteredList.size()]; 2879 filteredList.toArray(list); 2880 2881 return list; 2882 } 2883 2884 2910 public boolean createNewFile() throws IOException { 2911 if (enclArchive == null) 2912 return delegate.createNewFile(); 2913 try { 2914 return enclArchive.getArchiveController().createNewFile( 2915 enclEntryName, isLenient()); 2916 } catch (ArchiveController.FalsePositiveNativeException failure) { 2917 return delegate.createNewFile(); 2918 } catch (IOException failure) { 2919 throw failure; 2920 } 2921 } 2922 2923 public boolean mkdirs() { 2924 if (innerArchive == null) 2925 return delegate.mkdirs(); 2926 2927 final File parent = (File) getParentFile(); 2928 if (parent != null && !parent.exists()) 2929 parent.mkdirs(); 2930 2931 return mkdir(); 2935 } 2936 2937 2943 public boolean mkdir() { 2944 if (innerArchive == null) 2945 return delegate.mkdir(); 2946 try { 2947 return innerArchive.getArchiveController().mkdir( 2948 innerEntryName, isLenient()); 2949 } catch (ArchiveController.FalsePositiveNativeException failure) { 2950 assert !isArchive(); 2959 return delegate.mkdir(); 2960 } 2961 } 2962 2963 2988 public boolean delete() { 2989 if (innerArchive == null) 2990 return delegate.delete(); 2991 try { 2992 return innerArchive.getArchiveController().delete(innerEntryName); 2993 } catch (ArchiveController.FalsePositiveNativeException failure) { 2994 if (isArchive() 2995 && !delegate.isDirectory() 2996 && failure.getCause() instanceof FileNotFoundException) { 2997 return false; 2999 } else { 3000 return delegate.delete(); 3001 } 3002 } 3003 } 3004 3005 3017 public boolean deleteAll() { 3018 boolean ok = true; 3019 if (isDirectory()) { 3020 java.io.File [] members = listFiles(ArchiveDetector.NULL); 3021 for (int i = members.length; --i >= 0; ) 3022 ok &= ((File) members[i]).deleteAll(); 3023 } 3024 return ok && delete(); 3025 } 3026 3027 public void deleteOnExit() { 3028 if (innerArchive == null) { 3029 delegate.deleteOnExit(); 3030 return; 3031 } 3032 3033 if (isArchive()) { 3034 isDirectory(); 3038 } 3039 3040 ArchiveController.ShutdownHook.deleteOnExit.add(this); 3041 } 3042 3043 3047 public final boolean renameTo(final java.io.File dst) { 3048 return renameTo(dst, detector); 3049 } 3050 3051 3060 public boolean renameTo( 3061 final java.io.File dst, 3062 final ArchiveDetector detector) { 3063 3075 3076 if (innerArchive == null) { 3077 if (!(dst instanceof File) || ((File) dst).innerArchive == null) 3078 return delegate.renameTo(dst); 3079 } 3080 3081 return !dst.exists() 3082 && !contains(this, dst) 3083 && mv(this, dst, detector); 3084 } 3085 3086 private static boolean mv( 3087 final java.io.File src, 3088 final java.io.File dst, 3089 final ArchiveDetector detector) { 3090 boolean ok = true; 3091 if (src.isDirectory()) { 3092 dst.mkdir(); 3093 final String [] members = src.list(); 3096 if (dst instanceof File && ((File) dst).innerArchive != null) { 3097 Arrays.sort(members); 3100 } 3101 for (int i = 0, l = members.length; i < l; i++) { 3102 String member = members[i]; 3103 ok &= mv( 3104 detector.createFile(src, member), 3105 detector.createFile(dst, member), 3106 detector); 3107 } 3108 long srcLastModified = src.lastModified(); 3109 if (srcLastModified > 0 3111 || !(src instanceof File) || !((File) src).isEntry()) 3112 ok &= dst.setLastModified(srcLastModified); 3113 } else if (src.isFile()) { try { 3116 cp_p(src, dst); 3117 } catch (IOException failure) { 3118 ok = false; 3119 } 3120 } else { 3121 ok = false; 3122 } 3123 return ok && src.delete(); } 3125 3126 3172 public boolean copyFrom(final InputStream in) { 3173 try { 3174 final OutputStream out = detector.createFileOutputStream(this, false); 3175 try { 3176 cp(in, out); return true; 3178 } catch (IOException failure) { 3179 delete(); 3180 } 3181 } catch (IOException failure) { 3182 } 3183 return false; 3184 } 3185 3186 3235 public boolean copyFrom(final java.io.File src) { 3236 try { 3237 cp(src, this); 3238 return true; 3239 } catch (IOException failure) { 3240 return false; 3241 } 3242 } 3243 3244 3297 public boolean copyAllFrom(final java.io.File src) { 3298 return cp_r(src, this, detector, detector, false); 3299 } 3300 3301 3354 public boolean copyAllFrom( 3355 final java.io.File src, 3356 final ArchiveDetector detector) { 3357 return cp_r(src, this, detector, detector, false); 3358 } 3359 3360 3421 public boolean copyAllFrom( 3422 final java.io.File src, 3423 final ArchiveDetector srcDetector, 3424 final ArchiveDetector dstDetector) { 3425 return cp_r(src, this, srcDetector, dstDetector, false); 3426 } 3427 3428 3474 public boolean copyTo(final OutputStream out) { 3475 try { 3476 final InputStream in = detector.createFileInputStream(this); 3477 cp(in, out); return true; 3479 } catch (IOException failed) { 3480 return false; 3481 } 3482 } 3483 3484 3533 public boolean copyTo(final java.io.File dst) { 3534 try { 3535 cp(this, dst); 3536 return true; 3537 } catch (IOException failure) { 3538 return false; 3539 } 3540 } 3541 3542 3595 public boolean copyAllTo(final java.io.File dst) { 3596 return cp_r(this, dst, detector, detector, false); 3597 } 3598 3599 3653 public boolean copyAllTo( 3654 final java.io.File dst, 3655 final ArchiveDetector detector) { 3656 return cp_r(this, dst, detector, detector, false); 3657 } 3658 3659 3720 public boolean copyAllTo( 3721 final java.io.File dst, 3722 final ArchiveDetector srcDetector, 3723 final ArchiveDetector dstDetector) { 3724 return cp_r(this, dst, srcDetector, dstDetector, false); 3725 } 3726 3727 3779 public boolean archiveCopyFrom(final java.io.File src) { 3780 try { 3781 cp_p(src, this); 3782 return true; 3783 } catch (IOException failure) { 3784 return false; 3785 } 3786 } 3787 3788 3845 public boolean archiveCopyAllFrom(final java.io.File src) { 3846 return cp_r(src, this, detector, detector, true); 3847 } 3848 3849 3907 public boolean archiveCopyAllFrom( 3908 final java.io.File src, 3909 final ArchiveDetector detector) { 3910 return cp_r(src, this, detector, detector, true); 3911 } 3912 3913 3978 public boolean archiveCopyAllFrom( 3979 final java.io.File src, 3980 final ArchiveDetector srcDetector, 3981 final ArchiveDetector dstDetector) { 3982 return cp_r(src, this, srcDetector, dstDetector, true); 3983 } 3984 3985 4038 public boolean archiveCopyTo(java.io.File dst) { 4039 try { 4040 cp_p(this, dst); 4041 return true; 4042 } catch (IOException failure) { 4043 return false; 4044 } 4045 } 4046 4047 4104 public boolean archiveCopyAllTo(final java.io.File dst) { 4105 return cp_r(this, dst, detector, detector, true); 4106 } 4107 4108 4168 public boolean archiveCopyAllTo( 4169 final java.io.File dst, 4170 final ArchiveDetector detector) { 4171 return cp_r(this, dst, detector, detector, true); 4172 } 4173 4174 4239 public boolean archiveCopyAllTo( 4240 final java.io.File dst, 4241 final ArchiveDetector srcDetector, 4242 final ArchiveDetector dstDetector) { 4243 return cp_r(this, dst, srcDetector, dstDetector, true); 4244 } 4245 4246 4298 public static void cp( 4299 final InputStream in, 4300 final OutputStream out) 4301 throws IOException { 4302 try { 4303 try { 4304 cat(in, out); 4305 } finally { 4306 out.close(); 4307 } 4308 } finally { 4309 try { 4310 in.close(); 4311 } catch (IOException failure) { 4312 throw new InputIOException(failure); 4313 } 4314 } 4315 } 4316 4317 4382 public static final void cp(java.io.File src, java.io.File dst) 4383 throws IOException { 4384 cp(src, dst, false); 4385 } 4386 4387 4454 public static final void cp_p(java.io.File src, java.io.File dst) 4455 throws IOException { 4456 cp(src, dst, true); 4457 } 4458 4459 private static final void cp( 4460 final java.io.File src, 4461 final java.io.File dst, 4462 final boolean preserve) 4463 throws IOException { 4464 if (contains(src, dst)) 4465 throw new ContainsFileException(src, dst); 4466 cp0(src, dst, preserve); 4467 } 4468 4469 4472 private static void cp0( 4473 final java.io.File src, 4474 final java.io.File dst, 4475 final boolean preserve) 4476 throws IOException { 4477 try { 4478 ArchiveController.cp(src, dst, preserve); 4479 } catch (FileNotFoundException failure) { 4480 throw failure; 4481 } catch (IOException failure) { 4482 dst.delete(); 4483 throw failure; 4484 } 4485 } 4486 4487 private static final boolean cp_r( 4488 final java.io.File src, 4489 final java.io.File dst, 4490 final ArchiveDetector srcDetector, 4491 final ArchiveDetector dstDetector, 4492 final boolean preserve) { 4493 try { 4494 if (contains(src, dst)) 4495 return false; 4496 cp_r0(src, dst, srcDetector, dstDetector, preserve); 4497 return true; 4498 } catch (IOException failure) { 4499 return false; 4500 } 4501 } 4502 4503 4506 private static void cp_r0( 4507 final java.io.File src, 4508 final java.io.File dst, 4509 final ArchiveDetector srcDetector, 4510 final ArchiveDetector dstDetector, 4511 final boolean preserve) 4512 throws IOException { 4513 if (src.isDirectory()) { 4514 if (!dst.mkdir() && !dst.isDirectory()) 4515 throw new IOException("Destination is not a directory!"); 4516 final String [] members = src.list(); 4517 if (dst instanceof File && ((File) dst).innerArchive != null) { 4518 Arrays.sort(members); 4521 } 4522 for (int i = 0, l = members.length; i < l; i++) { 4523 final String member = members[i]; 4524 cp_r0( srcDetector.createFile(src, member), 4525 dstDetector.createFile(dst, member), 4526 srcDetector, dstDetector, 4527 preserve); 4528 } 4529 if (preserve) { 4530 long srcLastModified = src.lastModified(); 4531 if (srcLastModified > 0 4533 || !(src instanceof File) || !((File) src).isEntry()) 4534 if (!dst.setLastModified(srcLastModified)) 4535 throw new IOException("Cannot set last modification time!"); 4536 } 4537 } else if (src.isFile() && (!dst.exists() || dst.isFile())) { 4538 cp0(src, dst, preserve); 4539 } else { 4540 throw new IOException("Cannot copy non-existent or special files!"); 4541 } 4542 } 4543 4544 4591 public boolean catFrom(final InputStream in) { 4592 try { 4593 final OutputStream out = detector.createFileOutputStream(this, false); 4594 try { 4595 try { 4596 cat(in, out); 4597 } finally { 4598 out.close(); 4599 } 4600 return true; 4601 } catch (IOException failure) { 4602 delete(); 4603 } 4604 } catch (IOException failure) { 4605 } 4606 return false; 4607 } 4608 4609 4656 public boolean catTo(final OutputStream out) { 4657 try { 4658 final InputStream in = detector.createFileInputStream(this); 4659 try { 4660 cat(in, out); 4661 } finally { 4662 in.close(); 4663 } 4664 return true; 4665 } catch (IOException failure) { 4666 } 4667 return false; 4668 } 4669 4670 4720 public static void cat(final InputStream in, final OutputStream out) 4721 throws IOException { 4722 if (in == null || out == null) 4723 throw new NullPointerException (); 4724 4725 4740 4745 final Buffer[] buffers = allocateBuffers(); 4746 4747 4751 class Reader implements Runnable { 4752 4753 4754 int off; 4755 4756 4757 int len; 4758 4759 4760 volatile InputIOException exception; 4761 4762 public void run() { 4763 final InputStream _in = in; 4765 final Buffer[] _buffers = buffers; 4766 final int _buffersLen = buffers.length; 4767 4768 int read; 4773 do { 4774 final Buffer buffer; 4776 synchronized (this) { 4777 while (len >= _buffersLen) { 4778 try { 4779 wait(); 4780 } catch (InterruptedException interrupted) { 4781 return; 4782 } 4783 } 4784 buffer = _buffers[(off + len) % _buffersLen]; 4785 } 4786 4787 final byte[] buf = buffer.buf; 4792 try { 4793 read = _in.read(buf, 0, buf.length); 4794 } catch (IOException failure) { 4795 read = -1; 4796 exception = new InputIOException(failure); 4797 } 4798 if (Thread.interrupted()) 4799 read = -1; buffer.read = read; 4801 4802 synchronized (this) { 4804 len++; 4805 notify(); } 4807 } while (read != -1); 4808 } 4809 } 4811 try { 4812 final Reader reader = new Reader(); 4813 final Task task = readerExecutor.submit(reader); 4814 4815 final int buffersLen = buffers.length; 4817 4818 int write; 4819 while (true) { 4820 final int off; 4822 final Buffer buffer; 4823 synchronized (reader) { 4824 while (reader.len <= 0) { 4825 try { 4826 reader.wait(); 4827 } catch (InterruptedException ignored) { 4828 } 4829 } 4830 off = reader.off; 4831 buffer = buffers[off]; 4832 } 4833 4834 write = buffer.read; 4836 if (write == -1) 4837 break; 4839 final byte[] buf = buffer.buf; 4841 try { 4842 out.write(buf, 0, write); 4843 } catch (IOException failure) { 4844 task.cancel(); 4851 throw failure; 4852 } 4853 4854 synchronized (reader) { 4856 reader.off = (off + 1) % buffersLen; 4857 reader.len--; 4858 reader.notify(); } 4860 } 4861 4862 if (reader.exception != null) 4863 throw reader.exception; 4864 } finally { 4865 releaseBuffers(buffers); 4866 } 4867 } 4868 4869 private static Executor getExecutor(final String threadName) { 4870 try { 4871 final Class cl = Class.forName("de.schlichtherle.io.JSE5Executor"); 4873 final Constructor co = cl.getConstructor(new Class [] { String .class }); 4874 return (Executor) co.newInstance(new Object [] { threadName }); 4875 } catch (Throwable failure) { 4876 return new LegacyExecutor(threadName); 4877 } 4878 } 4879 4880 interface Executor { 4881 Task submit(Runnable target); 4882 } 4883 4884 interface Task { 4885 void cancel(); 4886 } 4887 4888 private static final Buffer[] allocateBuffers() { 4889 synchronized (Buffer.list) { 4890 Buffer[] buffers; 4891 for (Iterator i = Buffer.list.iterator(); i.hasNext(); ) { 4892 buffers = (Buffer[]) ((Reference) i.next()).get(); 4893 i.remove(); 4894 if (buffers != null) 4895 return buffers; 4896 } 4897 } 4898 4899 final Buffer[] buffers = new Buffer[4]; 4903 for (int i = buffers.length; --i >= 0; ) 4904 buffers[i] = new Buffer(); 4905 return buffers; 4906 } 4907 4908 private static final void releaseBuffers(Buffer[] buffers) { 4909 synchronized (Buffer.list) { 4910 Buffer.list.add(new SoftReference(buffers)); 4911 } 4912 } 4913 4914 private static final class Buffer { 4915 4919 static final List list = new LinkedList(); 4920 4921 4922 byte[] buf = new byte[64 * 1024]; 4924 4925 int read; 4926 } 4927} 4928
| Popular Tags
|