1 18 package org.apache.tools.ant.taskdefs; 19 20 import java.io.ByteArrayInputStream ; 21 import java.io.ByteArrayOutputStream ; 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.OutputStream ; 28 import java.util.ArrayList ; 29 import java.util.Enumeration ; 30 import java.util.Hashtable ; 31 import java.util.Iterator ; 32 import java.util.Stack ; 33 import java.util.Vector ; 34 import java.util.zip.CRC32 ; 35 36 import org.apache.tools.ant.BuildException; 37 import org.apache.tools.ant.DirectoryScanner; 38 import org.apache.tools.ant.FileScanner; 39 import org.apache.tools.ant.Project; 40 import org.apache.tools.ant.types.ArchiveFileSet; 41 import org.apache.tools.ant.types.EnumeratedAttribute; 42 import org.apache.tools.ant.types.FileSet; 43 import org.apache.tools.ant.types.PatternSet; 44 import org.apache.tools.ant.types.Resource; 45 import org.apache.tools.ant.types.ResourceCollection; 46 import org.apache.tools.ant.types.ZipFileSet; 47 import org.apache.tools.ant.types.ZipScanner; 48 import org.apache.tools.ant.types.resources.ArchiveResource; 49 import org.apache.tools.ant.types.resources.FileResource; 50 import org.apache.tools.ant.util.FileNameMapper; 51 import org.apache.tools.ant.util.FileUtils; 52 import org.apache.tools.ant.util.GlobPatternMapper; 53 import org.apache.tools.ant.util.IdentityMapper; 54 import org.apache.tools.ant.util.MergingMapper; 55 import org.apache.tools.ant.util.ResourceUtils; 56 import org.apache.tools.zip.ZipEntry; 57 import org.apache.tools.zip.ZipExtraField; 58 import org.apache.tools.zip.ZipFile; 59 import org.apache.tools.zip.ZipOutputStream; 60 61 68 public class Zip extends MatchingTask { 69 71 protected File zipFile; 72 private ZipScanner zs; 74 private File baseDir; 75 protected Hashtable entries = new Hashtable (); 76 private Vector groupfilesets = new Vector (); 77 private Vector filesetsFromGroupfilesets = new Vector (); 78 protected String duplicate = "add"; 79 private boolean doCompress = true; 80 private boolean doUpdate = false; 81 private boolean savedDoUpdate = false; 83 private boolean doFilesonly = false; 84 protected String archiveType = "zip"; 85 86 private static final long EMPTY_CRC = new CRC32 ().getValue (); 88 protected String emptyBehavior = "skip"; 89 private Vector resources = new Vector (); 90 protected Hashtable addedDirs = new Hashtable (); 91 private Vector addedFiles = new Vector (); 92 93 protected boolean doubleFilePass = false; 94 protected boolean skipWriting = false; 95 96 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 97 98 100 104 private boolean addingNewFiles = false; 105 106 110 private String encoding; 111 112 118 private boolean keepCompression = false; 119 120 126 private boolean roundUp = true; 127 128 132 private String comment = ""; 133 134 private int level = ZipOutputStream.DEFAULT_COMPRESSION; 135 136 144 public void setZipfile(File zipFile) { 145 setDestFile(zipFile); 146 } 147 148 157 public void setFile(File file) { 158 setDestFile(file); 159 } 160 161 162 167 public void setDestFile(File destFile) { 168 this.zipFile = destFile; 169 } 170 171 176 public File getDestFile() { 177 return zipFile; 178 } 179 180 181 185 public void setBasedir(File baseDir) { 186 this.baseDir = baseDir; 187 } 188 189 194 public void setCompress(boolean c) { 195 doCompress = c; 196 } 197 198 203 public boolean isCompress() { 204 return doCompress; 205 } 206 207 212 public void setFilesonly(boolean f) { 213 doFilesonly = f; 214 } 215 216 221 public void setUpdate(boolean c) { 222 doUpdate = c; 223 savedDoUpdate = c; 224 } 225 226 230 public boolean isInUpdateMode() { 231 return doUpdate; 232 } 233 234 238 public void addFileset(FileSet set) { 239 add(set); 240 } 241 242 247 public void addZipfileset(ZipFileSet set) { 248 add(set); 249 } 250 251 256 public void add(ResourceCollection a) { 257 resources.add(a); 258 } 259 260 264 public void addZipGroupFileset(FileSet set) { 265 groupfilesets.addElement(set); 266 } 267 268 277 public void setDuplicate(Duplicate df) { 278 duplicate = df.getValue(); 279 } 280 281 285 public static class WhenEmpty extends EnumeratedAttribute { 286 290 public String [] getValues() { 291 return new String [] {"fail", "skip", "create"}; 292 } 293 } 294 295 305 public void setWhenempty(WhenEmpty we) { 306 emptyBehavior = we.getValue(); 307 } 308 309 317 public void setEncoding(String encoding) { 318 this.encoding = encoding; 319 } 320 321 326 public String getEncoding() { 327 return encoding; 328 } 329 330 337 public void setKeepCompression(boolean keep) { 338 keepCompression = keep; 339 } 340 341 347 public void setComment(String comment) { 348 this.comment = comment; 349 } 350 351 357 public String getComment() { 358 return comment; 359 } 360 361 367 public void setLevel(int level) { 368 this.level = level; 369 } 370 371 376 public int getLevel() { 377 return level; 378 } 379 380 394 public void setRoundUp(boolean r) { 395 roundUp = r; 396 } 397 398 402 public void execute() throws BuildException { 403 404 if (doubleFilePass) { 405 skipWriting = true; 406 executeMain(); 407 skipWriting = false; 408 executeMain(); 409 } else { 410 executeMain(); 411 } 412 } 413 414 419 public void executeMain() throws BuildException { 420 421 if (baseDir == null && resources.size() == 0 422 && groupfilesets.size() == 0 && "zip".equals(archiveType)) { 423 throw new BuildException("basedir attribute must be set, " 424 + "or at least one " 425 + "resource collection must be given!"); 426 } 427 428 if (zipFile == null) { 429 throw new BuildException("You must specify the " 430 + archiveType + " file to create!"); 431 } 432 433 if (zipFile.exists() && !zipFile.isFile()) { 434 throw new BuildException(zipFile + " is not a file."); 435 } 436 437 if (zipFile.exists() && !zipFile.canWrite()) { 438 throw new BuildException(zipFile + " is read-only."); 439 } 440 441 File renamedFile = null; 443 addingNewFiles = true; 444 445 if (doUpdate && !zipFile.exists()) { 448 doUpdate = false; 449 log("ignoring update attribute as " + archiveType 450 + " doesn't exist.", Project.MSG_DEBUG); 451 } 452 453 for (int i = 0; i < groupfilesets.size(); i++) { 455 456 log("Processing groupfileset ", Project.MSG_VERBOSE); 457 FileSet fs = (FileSet) groupfilesets.elementAt(i); 458 FileScanner scanner = fs.getDirectoryScanner(getProject()); 459 String [] files = scanner.getIncludedFiles(); 460 File basedir = scanner.getBasedir(); 461 for (int j = 0; j < files.length; j++) { 462 463 log("Adding file " + files[j] + " to fileset", 464 Project.MSG_VERBOSE); 465 ZipFileSet zf = new ZipFileSet(); 466 zf.setProject(getProject()); 467 zf.setSrc(new File (basedir, files[j])); 468 add(zf); 469 filesetsFromGroupfilesets.addElement(zf); 470 } 471 } 472 473 Vector vfss = new Vector (); 475 if (baseDir != null) { 476 FileSet fs = (FileSet) getImplicitFileSet().clone(); 477 fs.setDir(baseDir); 478 vfss.addElement(fs); 479 } 480 for (int i = 0; i < resources.size(); i++) { 481 ResourceCollection rc = (ResourceCollection) resources.elementAt(i); 482 vfss.addElement(rc); 483 } 484 485 ResourceCollection[] fss = new ResourceCollection[vfss.size()]; 486 vfss.copyInto(fss); 487 boolean success = false; 488 try { 489 ArchiveState state = getResourcesToAdd(fss, zipFile, false); 491 492 if (!state.isOutOfDate()) { 494 return; 495 } 496 497 if (!zipFile.exists() && state.isWithoutAnyResources()) { 498 createEmptyZip(zipFile); 499 return; 500 } 501 Resource[][] addThem = state.getResourcesToAdd(); 502 503 if (doUpdate) { 504 renamedFile = 505 FILE_UTILS.createTempFile("zip", ".tmp", 506 zipFile.getParentFile()); 507 renamedFile.deleteOnExit(); 508 509 try { 510 FILE_UTILS.rename(zipFile, renamedFile); 511 } catch (SecurityException e) { 512 throw new BuildException( 513 "Not allowed to rename old file (" 514 + zipFile.getAbsolutePath() 515 + ") to temporary file"); 516 } catch (IOException e) { 517 throw new BuildException( 518 "Unable to rename old file (" 519 + zipFile.getAbsolutePath() 520 + ") to temporary file"); 521 } 522 } 523 524 String action = doUpdate ? "Updating " : "Building "; 525 526 log(action + archiveType + ": " + zipFile.getAbsolutePath()); 527 528 ZipOutputStream zOut = null; 529 try { 530 if (!skipWriting) { 531 zOut = new ZipOutputStream(zipFile); 532 533 zOut.setEncoding(encoding); 534 zOut.setMethod(doCompress 535 ? ZipOutputStream.DEFLATED : ZipOutputStream.STORED); 536 zOut.setLevel(level); 537 } 538 initZipOutputStream(zOut); 539 540 for (int i = 0; i < fss.length; i++) { 542 if (addThem[i].length != 0) { 543 addResources(fss[i], addThem[i], zOut); 544 } 545 } 546 547 if (doUpdate) { 548 addingNewFiles = false; 549 ZipFileSet oldFiles = new ZipFileSet(); 550 oldFiles.setProject(getProject()); 551 oldFiles.setSrc(renamedFile); 552 oldFiles.setDefaultexcludes(false); 553 554 for (int i = 0; i < addedFiles.size(); i++) { 555 PatternSet.NameEntry ne = oldFiles.createExclude(); 556 ne.setName((String ) addedFiles.elementAt(i)); 557 } 558 DirectoryScanner ds = 559 oldFiles.getDirectoryScanner(getProject()); 560 ((ZipScanner) ds).setEncoding(encoding); 561 562 String [] f = ds.getIncludedFiles(); 563 Resource[] r = new Resource[f.length]; 564 for (int i = 0; i < f.length; i++) { 565 r[i] = ds.getResource(f[i]); 566 } 567 568 if (!doFilesonly) { 569 String [] d = ds.getIncludedDirectories(); 570 Resource[] dr = new Resource[d.length]; 571 for (int i = 0; i < d.length; i++) { 572 dr[i] = ds.getResource(d[i]); 573 } 574 Resource[] tmp = r; 575 r = new Resource[tmp.length + dr.length]; 576 System.arraycopy(dr, 0, r, 0, dr.length); 577 System.arraycopy(tmp, 0, r, dr.length, tmp.length); 578 } 579 addResources(oldFiles, r, zOut); 580 } 581 if (zOut != null) { 582 zOut.setComment(comment); 583 } 584 finalizeZipOutputStream(zOut); 585 586 if (doUpdate) { 589 if (!renamedFile.delete()) { 590 log ("Warning: unable to delete temporary file " 591 + renamedFile.getName(), Project.MSG_WARN); 592 } 593 } 594 success = true; 595 } finally { 596 try { 598 if (zOut != null) { 599 zOut.close(); 600 } 601 } catch (IOException ex) { 602 if (success) { 612 throw ex; 613 } 614 } 615 } 616 } catch (IOException ioe) { 617 String msg = "Problem creating " + archiveType + ": " 618 + ioe.getMessage(); 619 620 if ((!doUpdate || renamedFile != null) && !zipFile.delete()) { 622 msg += " (and the archive is probably corrupt but I could not " 623 + "delete it)"; 624 } 625 626 if (doUpdate && renamedFile != null) { 627 try { 628 FILE_UTILS.rename(renamedFile, zipFile); 629 } catch (IOException e) { 630 msg += " (and I couldn't rename the temporary file " 631 + renamedFile.getName() + " back)"; 632 } 633 } 634 635 throw new BuildException(msg, ioe, getLocation()); 636 } finally { 637 cleanUp(); 638 } 639 } 640 641 646 protected final boolean isAddingNewFiles() { 647 return addingNewFiles; 648 } 649 650 661 protected final void addResources(FileSet fileset, Resource[] resources, 662 ZipOutputStream zOut) 663 throws IOException { 664 665 String prefix = ""; 666 String fullpath = ""; 667 int dirMode = ArchiveFileSet.DEFAULT_DIR_MODE; 668 int fileMode = ArchiveFileSet.DEFAULT_FILE_MODE; 669 670 ArchiveFileSet zfs = null; 671 if (fileset instanceof ArchiveFileSet) { 672 zfs = (ArchiveFileSet) fileset; 673 prefix = zfs.getPrefix(getProject()); 674 fullpath = zfs.getFullpath(getProject()); 675 dirMode = zfs.getDirMode(getProject()); 676 fileMode = zfs.getFileMode(getProject()); 677 } 678 679 if (prefix.length() > 0 && fullpath.length() > 0) { 680 throw new BuildException("Both prefix and fullpath attributes must" 681 + " not be set on the same fileset."); 682 } 683 684 if (resources.length != 1 && fullpath.length() > 0) { 685 throw new BuildException("fullpath attribute may only be specified" 686 + " for filesets that specify a single" 687 + " file."); 688 } 689 690 if (prefix.length() > 0) { 691 if (!prefix.endsWith("/") && !prefix.endsWith("\\")) { 692 prefix += "/"; 693 } 694 addParentDirs(null, prefix, zOut, "", dirMode); 695 } 696 697 ZipFile zf = null; 698 try { 699 boolean dealingWithFiles = false; 700 File base = null; 701 702 if (zfs == null || zfs.getSrc(getProject()) == null) { 703 dealingWithFiles = true; 704 base = fileset.getDir(getProject()); 705 } else if (zfs instanceof ZipFileSet) { 706 zf = new ZipFile(zfs.getSrc(getProject()), encoding); 707 } 708 709 for (int i = 0; i < resources.length; i++) { 710 String name = null; 711 if (fullpath.length() > 0) { 712 name = fullpath; 713 } else { 714 name = resources[i].getName(); 715 } 716 name = name.replace(File.separatorChar, '/'); 717 718 if ("".equals(name)) { 719 continue; 720 } 721 if (resources[i].isDirectory() && !name.endsWith("/")) { 722 name = name + "/"; 723 } 724 725 if (!doFilesonly && !dealingWithFiles 726 && resources[i].isDirectory() 727 && !zfs.hasDirModeBeenSet()) { 728 int nextToLastSlash = name.lastIndexOf("/", 729 name.length() - 2); 730 if (nextToLastSlash != -1) { 731 addParentDirs(base, name.substring(0, 732 nextToLastSlash + 1), 733 zOut, prefix, dirMode); 734 } 735 if (zf != null) { 736 ZipEntry ze = zf.getEntry(resources[i].getName()); 737 addParentDirs(base, name, zOut, prefix, 738 ze.getUnixMode()); 739 } else { 740 ArchiveResource tr = (ArchiveResource) resources[i]; 741 addParentDirs(base, name, zOut, prefix, 742 tr.getMode()); 743 } 744 745 } else { 746 addParentDirs(base, name, zOut, prefix, dirMode); 747 } 748 749 if (!resources[i].isDirectory() && dealingWithFiles) { 750 File f = FILE_UTILS.resolveFile(base, 751 resources[i].getName()); 752 zipFile(f, zOut, prefix + name, fileMode); 753 } else if (!resources[i].isDirectory()) { 754 if (zf != null) { 755 ZipEntry ze = zf.getEntry(resources[i].getName()); 756 757 if (ze != null) { 758 boolean oldCompress = doCompress; 759 if (keepCompression) { 760 doCompress = (ze.getMethod() == ZipEntry.DEFLATED); 761 } 762 try { 763 zipFile(zf.getInputStream(ze), zOut, prefix + name, 764 ze.getTime(), zfs.getSrc(getProject()), 765 zfs.hasFileModeBeenSet() ? fileMode 766 : ze.getUnixMode()); 767 } finally { 768 doCompress = oldCompress; 769 } 770 } 771 } else { 772 ArchiveResource tr = (ArchiveResource) resources[i]; 773 InputStream is = null; 774 try { 775 is = tr.getInputStream(); 776 zipFile(is, zOut, prefix + name, 777 resources[i].getLastModified(), 778 zfs.getSrc(getProject()), 779 zfs.hasFileModeBeenSet() ? fileMode 780 : tr.getMode()); 781 } finally { 782 FileUtils.close(is); 783 } 784 } 785 } 786 } 787 } finally { 788 if (zf != null) { 789 zf.close(); 790 } 791 } 792 } 793 794 805 protected final void addResources(ResourceCollection rc, 806 Resource[] resources, 807 ZipOutputStream zOut) 808 throws IOException { 809 if (rc instanceof FileSet) { 810 addResources((FileSet) rc, resources, zOut); 811 return; 812 } 813 for (int i = 0; i < resources.length; i++) { 814 String name = resources[i].getName().replace(File.separatorChar, 815 '/'); 816 if ("".equals(name)) { 817 continue; 818 } 819 if (resources[i].isDirectory() && doFilesonly) { 820 continue; 821 } 822 File base = null; 823 if (resources[i] instanceof FileResource) { 824 base = ((FileResource) resources[i]).getBaseDir(); 825 } 826 if (resources[i].isDirectory()) { 827 if (!name.endsWith("/")) { 828 name = name + "/"; 829 } 830 } 831 832 addParentDirs(base, name, zOut, "", 833 ArchiveFileSet.DEFAULT_DIR_MODE); 834 835 if (!resources[i].isDirectory()) { 836 if (resources[i] instanceof FileResource) { 837 File f = ((FileResource) resources[i]).getFile(); 838 zipFile(f, zOut, name, ArchiveFileSet.DEFAULT_FILE_MODE); 839 } else { 840 InputStream is = null; 841 try { 842 is = resources[i].getInputStream(); 843 zipFile(is, zOut, name, 844 resources[i].getLastModified(), 845 null, ArchiveFileSet.DEFAULT_FILE_MODE); 846 } finally { 847 FileUtils.close(is); 848 } 849 } 850 } 851 } 852 } 853 854 860 protected void initZipOutputStream(ZipOutputStream zOut) 861 throws IOException , BuildException { 862 } 863 864 870 protected void finalizeZipOutputStream(ZipOutputStream zOut) 871 throws IOException , BuildException { 872 } 873 874 880 protected boolean createEmptyZip(File zipFile) throws BuildException { 881 log("Note: creating empty " + archiveType + " archive " + zipFile, 885 Project.MSG_INFO); 886 OutputStream os = null; 887 try { 888 os = new FileOutputStream (zipFile); 889 byte[] empty = new byte[22]; 891 empty[0] = 80; empty[1] = 75; empty[2] = 5; 894 empty[3] = 6; 895 os.write(empty); 897 } catch (IOException ioe) { 898 throw new BuildException("Could not create empty ZIP archive " 899 + "(" + ioe.getMessage() + ")", ioe, 900 getLocation()); 901 } finally { 902 if (os != null) { 903 try { 904 os.close(); 905 } catch (IOException e) { 906 } 908 } 909 } 910 return true; 911 } 912 913 916 private synchronized ZipScanner getZipScanner() { 917 if (zs == null) { 918 zs = new ZipScanner(); 919 zs.setEncoding(encoding); 920 zs.setSrc(zipFile); 921 } 922 return zs; 923 } 924 925 953 protected ArchiveState getResourcesToAdd(ResourceCollection[] rcs, 954 File zipFile, 955 boolean needsUpdate) 956 throws BuildException { 957 ArrayList filesets = new ArrayList (); 958 ArrayList rest = new ArrayList (); 959 for (int i = 0; i < rcs.length; i++) { 960 if (rcs[i] instanceof FileSet) { 961 filesets.add(rcs[i]); 962 } else { 963 rest.add(rcs[i]); 964 } 965 } 966 ResourceCollection[] rc = (ResourceCollection[]) 967 rest.toArray(new ResourceCollection[rest.size()]); 968 ArchiveState as = getNonFileSetResourcesToAdd(rc, zipFile, 969 needsUpdate); 970 971 FileSet[] fs = (FileSet[]) filesets.toArray(new FileSet[filesets 972 .size()]); 973 ArchiveState as2 = getResourcesToAdd(fs, zipFile, as.isOutOfDate()); 974 if (!as.isOutOfDate() && as2.isOutOfDate()) { 975 983 as = getNonFileSetResourcesToAdd(rc, zipFile, true); 984 } 985 986 Resource[][] toAdd = new Resource[rcs.length][]; 987 int fsIndex = 0; 988 int restIndex = 0; 989 for (int i = 0; i < rcs.length; i++) { 990 if (rcs[i] instanceof FileSet) { 991 toAdd[i] = as2.getResourcesToAdd()[fsIndex++]; 992 } else { 993 toAdd[i] = as.getResourcesToAdd()[restIndex++]; 994 } 995 } 996 return new ArchiveState(as2.isOutOfDate(), toAdd); 997 } 998 999 1021 protected ArchiveState getResourcesToAdd(FileSet[] filesets, 1022 File zipFile, 1023 boolean needsUpdate) 1024 throws BuildException { 1025 1026 Resource[][] initialResources = grabResources(filesets); 1027 if (isEmpty(initialResources)) { 1028 if (needsUpdate && doUpdate) { 1029 1045 return new ArchiveState(true, initialResources); 1046 } 1047 1048 if (emptyBehavior.equals("skip")) { 1049 if (doUpdate) { 1050 log(archiveType + " archive " + zipFile 1051 + " not updated because no new files were included.", 1052 Project.MSG_VERBOSE); 1053 } else { 1054 log("Warning: skipping " + archiveType + " archive " 1055 + zipFile + " because no files were included.", 1056 Project.MSG_WARN); 1057 } 1058 } else if (emptyBehavior.equals("fail")) { 1059 throw new BuildException("Cannot create " + archiveType 1060 + " archive " + zipFile 1061 + ": no files were included.", 1062 getLocation()); 1063 } else { 1064 if (!zipFile.exists()) { 1066 needsUpdate = true; 1067 } 1068 } 1069 return new ArchiveState(needsUpdate, initialResources); 1070 } 1071 1072 1074 if (!zipFile.exists()) { 1075 return new ArchiveState(true, initialResources); 1076 } 1077 1078 if (needsUpdate && !doUpdate) { 1079 return new ArchiveState(true, initialResources); 1081 } 1082 1083 Resource[][] newerResources = new Resource[filesets.length][]; 1084 1085 for (int i = 0; i < filesets.length; i++) { 1086 if (!(fileset instanceof ZipFileSet) 1087 || ((ZipFileSet) fileset).getSrc(getProject()) == null) { 1088 File base = filesets[i].getDir(getProject()); 1089 1090 for (int j = 0; j < initialResources[i].length; j++) { 1091 File resourceAsFile = 1092 FILE_UTILS.resolveFile(base, 1093 initialResources[i][j].getName()); 1094 if (resourceAsFile.equals(zipFile)) { 1095 throw new BuildException("A zip file cannot include " 1096 + "itself", getLocation()); 1097 } 1098 } 1099 } 1100 } 1101 1102 for (int i = 0; i < filesets.length; i++) { 1103 if (initialResources[i].length == 0) { 1104 newerResources[i] = new Resource[] {}; 1105 continue; 1106 } 1107 1108 FileNameMapper myMapper = new IdentityMapper(); 1109 if (filesets[i] instanceof ZipFileSet) { 1110 ZipFileSet zfs = (ZipFileSet) filesets[i]; 1111 if (zfs.getFullpath(getProject()) != null 1112 && !zfs.getFullpath(getProject()).equals("")) { 1113 MergingMapper fm = new MergingMapper(); 1117 fm.setTo(zfs.getFullpath(getProject())); 1118 myMapper = fm; 1119 1120 } else if (zfs.getPrefix(getProject()) != null 1121 && !zfs.getPrefix(getProject()).equals("")) { 1122 GlobPatternMapper gm = new GlobPatternMapper(); 1123 gm.setFrom("*"); 1124 String prefix = zfs.getPrefix(getProject()); 1125 if (!prefix.endsWith("/") && !prefix.endsWith("\\")) { 1126 prefix += "/"; 1127 } 1128 gm.setTo(prefix + "*"); 1129 myMapper = gm; 1130 } 1131 } 1132 1133 Resource[] resources = initialResources[i]; 1134 if (doFilesonly) { 1135 resources = selectFileResources(resources); 1136 } 1137 1138 newerResources[i] = 1139 ResourceUtils.selectOutOfDateSources(this, 1140 resources, 1141 myMapper, 1142 getZipScanner()); 1143 needsUpdate = needsUpdate || (newerResources[i].length > 0); 1144 1145 if (needsUpdate && !doUpdate) { 1146 break; 1149 } 1150 } 1151 1152 if (needsUpdate && !doUpdate) { 1153 return new ArchiveState(true, initialResources); 1155 } 1156 1157 return new ArchiveState(needsUpdate, newerResources); 1158 } 1159 1160 1182 protected ArchiveState getNonFileSetResourcesToAdd(ResourceCollection[] rcs, 1183 File zipFile, 1184 boolean needsUpdate) 1185 throws BuildException { 1186 1190 1191 Resource[][] initialResources = grabNonFileSetResources(rcs); 1192 if (isEmpty(initialResources)) { 1193 return new ArchiveState(needsUpdate, initialResources); 1196 } 1197 1198 1200 if (!zipFile.exists()) { 1201 return new ArchiveState(true, initialResources); 1202 } 1203 1204 if (needsUpdate && !doUpdate) { 1205 return new ArchiveState(true, initialResources); 1207 } 1208 1209 Resource[][] newerResources = new Resource[rcs.length][]; 1210 1211 for (int i = 0; i < rcs.length; i++) { 1212 if (initialResources[i].length == 0) { 1213 newerResources[i] = new Resource[] {}; 1214 continue; 1215 } 1216 1217 for (int j = 0; j < initialResources[i].length; j++) { 1218 if (initialResources[i][j] instanceof FileResource 1219 && zipFile.equals(((FileResource) 1220 initialResources[i][j]).getFile())) { 1221 throw new BuildException("A zip file cannot include " 1222 + "itself", getLocation()); 1223 } 1224 } 1225 1226 Resource[] rs = initialResources[i]; 1227 if (doFilesonly) { 1228 rs = selectFileResources(rs); 1229 } 1230 1231 newerResources[i] = 1232 ResourceUtils.selectOutOfDateSources(this, 1233 rs, 1234 new IdentityMapper(), 1235 getZipScanner()); 1236 needsUpdate = needsUpdate || (newerResources[i].length > 0); 1237 1238 if (needsUpdate && !doUpdate) { 1239 break; 1242 } 1243 } 1244 1245 if (needsUpdate && !doUpdate) { 1246 return new ArchiveState(true, initialResources); 1248 } 1249 1250 return new ArchiveState(needsUpdate, newerResources); 1251 } 1252 1253 1261 protected Resource[][] grabResources(FileSet[] filesets) { 1262 Resource[][] result = new Resource[filesets.length][]; 1263 for (int i = 0; i < filesets.length; i++) { 1264 boolean skipEmptyNames = true; 1265 if (filesets[i] instanceof ZipFileSet) { 1266 ZipFileSet zfs = (ZipFileSet) filesets[i]; 1267 skipEmptyNames = zfs.getPrefix(getProject()).equals("") 1268 && zfs.getFullpath(getProject()).equals(""); 1269 } 1270 DirectoryScanner rs = 1271 filesets[i].getDirectoryScanner(getProject()); 1272 if (rs instanceof ZipScanner) { 1273 ((ZipScanner) rs).setEncoding(encoding); 1274 } 1275 Vector resources = new Vector (); 1276 if (!doFilesonly) { 1277 String [] directories = rs.getIncludedDirectories(); 1278 for (int j = 0; j < directories.length; j++) { 1279 if (!"".equals(directories[j]) || !skipEmptyNames) { 1280 resources.addElement(rs.getResource(directories[j])); 1281 } 1282 } 1283 } 1284 String [] files = rs.getIncludedFiles(); 1285 for (int j = 0; j < files.length; j++) { 1286 if (!"".equals(files[j]) || !skipEmptyNames) { 1287 resources.addElement(rs.getResource(files[j])); 1288 } 1289 } 1290 1291 result[i] = new Resource[resources.size()]; 1292 resources.copyInto(result[i]); 1293 } 1294 return result; 1295 } 1296 1297 1305 protected Resource[][] grabNonFileSetResources(ResourceCollection[] rcs) { 1306 Resource[][] result = new Resource[rcs.length][]; 1307 for (int i = 0; i < rcs.length; i++) { 1308 Iterator iter = rcs[i].iterator(); 1309 ArrayList rs = new ArrayList (); 1310 int lastDir = 0; 1311 while (iter.hasNext()) { 1312 Resource r = (Resource) iter.next(); 1313 if (r.isExists()) { 1314 if (r.isDirectory()) { 1315 rs.add(lastDir++, r); 1316 } else { 1317 rs.add(r); 1318 } 1319 } 1320 } 1321 result[i] = (Resource[]) rs.toArray(new Resource[rs.size()]); 1322 } 1323 return result; 1324 } 1325 1326 1335 protected void zipDir(File dir, ZipOutputStream zOut, String vPath, 1336 int mode) 1337 throws IOException { 1338 zipDir(dir, zOut, vPath, mode, null); 1339 } 1340 1341 1351 protected void zipDir(File dir, ZipOutputStream zOut, String vPath, 1352 int mode, ZipExtraField[] extra) 1353 throws IOException { 1354 if (doFilesonly) { 1355 log("skipping directory " + vPath + " for file-only archive", 1356 Project.MSG_VERBOSE); 1357 return; 1358 } 1359 if (addedDirs.get(vPath) != null) { 1360 return; 1363 } 1364 1365 log("adding directory " + vPath, Project.MSG_VERBOSE); 1366 addedDirs.put(vPath, vPath); 1367 1368 if (!skipWriting) { 1369 ZipEntry ze = new ZipEntry (vPath); 1370 if (dir != null && dir.exists()) { 1371 ze.setTime(dir.lastModified() + (roundUp ? 1999 : 0)); 1373 } else { 1374 ze.setTime(System.currentTimeMillis() + (roundUp ? 1999 : 0)); 1376 } 1377 ze.setSize (0); 1378 ze.setMethod (ZipEntry.STORED); 1379 ze.setCrc (EMPTY_CRC); 1381 ze.setUnixMode(mode); 1382 1383 if (extra != null) { 1384 ze.setExtraFields(extra); 1385 } 1386 1387 zOut.putNextEntry(ze); 1388 } 1389 } 1390 1391 1405 protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath, 1406 long lastModified, File fromArchive, int mode) 1407 throws IOException { 1408 if (entries.contains(vPath)) { 1409 1410 if (duplicate.equals("preserve")) { 1411 log(vPath + " already added, skipping", Project.MSG_INFO); 1412 return; 1413 } else if (duplicate.equals("fail")) { 1414 throw new BuildException("Duplicate file " + vPath 1415 + " was found and the duplicate " 1416 + "attribute is 'fail'."); 1417 } else { 1418 log("duplicate file " + vPath 1420 + " found, adding.", Project.MSG_VERBOSE); 1421 } 1422 } else { 1423 log("adding entry " + vPath, Project.MSG_VERBOSE); 1424 } 1425 1426 entries.put(vPath, vPath); 1427 1428 if (!skipWriting) { 1429 ZipEntry ze = new ZipEntry(vPath); 1430 ze.setTime(lastModified); 1431 ze.setMethod(doCompress ? ZipEntry.DEFLATED : ZipEntry.STORED); 1432 1433 1440 if (!zOut.isSeekable() && !doCompress) { 1441 long size = 0; 1442 CRC32 cal = new CRC32 (); 1443 if (!in.markSupported()) { 1444 ByteArrayOutputStream bos = new ByteArrayOutputStream (); 1446 1447 byte[] buffer = new byte[8 * 1024]; 1448 int count = 0; 1449 do { 1450 size += count; 1451 cal.update(buffer, 0, count); 1452 bos.write(buffer, 0, count); 1453 count = in.read(buffer, 0, buffer.length); 1454 } while (count != -1); 1455 in = new ByteArrayInputStream (bos.toByteArray()); 1456 1457 } else { 1458 in.mark(Integer.MAX_VALUE); 1459 byte[] buffer = new byte[8 * 1024]; 1460 int count = 0; 1461 do { 1462 size += count; 1463 cal.update(buffer, 0, count); 1464 count = in.read(buffer, 0, buffer.length); 1465 } while (count != -1); 1466 in.reset(); 1467 } 1468 ze.setSize(size); 1469 ze.setCrc(cal.getValue()); 1470 } 1471 1472 ze.setUnixMode(mode); 1473 zOut.putNextEntry(ze); 1474 1475 byte[] buffer = new byte[8 * 1024]; 1476 int count = 0; 1477 do { 1478 if (count != 0) { 1479 zOut.write(buffer, 0, count); 1480 } 1481 count = in.read(buffer, 0, buffer.length); 1482 } while (count != -1); 1483 } 1484 addedFiles.addElement(vPath); 1485 } 1486 1487 1500 protected void zipFile(File file, ZipOutputStream zOut, String vPath, 1501 int mode) 1502 throws IOException { 1503 if (file.equals(zipFile)) { 1504 throw new BuildException("A zip file cannot include itself", 1505 getLocation()); 1506 } 1507 1508 FileInputStream fIn = new FileInputStream (file); 1509 try { 1510 zipFile(fIn, zOut, vPath, 1512 file.lastModified() + (roundUp ? 1999 : 0), 1513 null, mode); 1514 } finally { 1515 fIn.close(); 1516 } 1517 } 1518 1519 1529 protected final void addParentDirs(File baseDir, String entry, 1530 ZipOutputStream zOut, String prefix, 1531 int dirMode) 1532 throws IOException { 1533 if (!doFilesonly) { 1534 Stack directories = new Stack (); 1535 int slashPos = entry.length(); 1536 1537 while ((slashPos = entry.lastIndexOf('/', slashPos - 1)) != -1) { 1538 String dir = entry.substring(0, slashPos + 1); 1539 if (addedDirs.get(prefix + dir) != null) { 1540 break; 1541 } 1542 directories.push(dir); 1543 } 1544 1545 while (!directories.isEmpty()) { 1546 String dir = (String ) directories.pop(); 1547 File f = null; 1548 if (baseDir != null) { 1549 f = new File (baseDir, dir); 1550 } else { 1551 f = new File (dir); 1552 } 1553 zipDir(f, zOut, prefix + dir, dirMode); 1554 } 1555 } 1556 } 1557 1558 1572 protected void cleanUp() { 1573 addedDirs.clear(); 1574 addedFiles.removeAllElements(); 1575 entries.clear(); 1576 addingNewFiles = false; 1577 doUpdate = savedDoUpdate; 1578 Enumeration e = filesetsFromGroupfilesets.elements(); 1579 while (e.hasMoreElements()) { 1580 ZipFileSet zf = (ZipFileSet) e.nextElement(); 1581 resources.removeElement(zf); 1582 } 1583 filesetsFromGroupfilesets.removeAllElements(); 1584 } 1585 1586 1594 public void reset() { 1595 resources.removeAllElements(); 1596 zipFile = null; 1597 baseDir = null; 1598 groupfilesets.removeAllElements(); 1599 duplicate = "add"; 1600 archiveType = "zip"; 1601 doCompress = true; 1602 emptyBehavior = "skip"; 1603 doUpdate = false; 1604 doFilesonly = false; 1605 encoding = null; 1606 } 1607 1608 1615 protected static final boolean isEmpty(Resource[][] r) { 1616 for (int i = 0; i < r.length; i++) { 1617 if (r[i].length > 0) { 1618 return false; 1619 } 1620 } 1621 return true; 1622 } 1623 1624 1630 protected Resource[] selectFileResources(Resource[] orig) { 1631 if (orig.length == 0) { 1632 return orig; 1633 } 1634 1635 Vector v = new Vector (orig.length); 1636 for (int i = 0; i < orig.length; i++) { 1637 if (!orig[i].isDirectory()) { 1638 v.addElement(orig[i]); 1639 } else { 1640 log("Ignoring directory " + orig[i].getName() 1641 + " as only files will be added.", Project.MSG_VERBOSE); 1642 } 1643 } 1644 1645 if (v.size() != orig.length) { 1646 Resource[] r = new Resource[v.size()]; 1647 v.copyInto(r); 1648 return r; 1649 } 1650 return orig; 1651 } 1652 1653 1657 public static class Duplicate extends EnumeratedAttribute { 1658 1661 1662 public String [] getValues() { 1663 return new String [] {"add", "preserve", "fail"}; 1664 } 1665 } 1666 1667 1673 public static class ArchiveState { 1674 private boolean outOfDate; 1675 private Resource[][] resourcesToAdd; 1676 1677 ArchiveState(boolean state, Resource[][] r) { 1678 outOfDate = state; 1679 resourcesToAdd = r; 1680 } 1681 1682 1686 public boolean isOutOfDate() { 1687 return outOfDate; 1688 } 1689 1690 1694 public Resource[][] getResourcesToAdd() { 1695 return resourcesToAdd; 1696 } 1697 1702 public boolean isWithoutAnyResources() { 1703 if (resourcesToAdd == null) { 1704 return true; 1705 } 1706 for (int counter = 0; counter < resourcesToAdd.length; counter++) { 1707 if (resourcesToAdd[counter] != null) { 1708 if (resourcesToAdd[counter].length > 0) { 1709 return false; 1710 } 1711 } 1712 } 1713 return true; 1714 } 1715 } 1716} 1717 | Popular Tags |