001: package com.ice.jcvsweb.helper;
002:
003: import java.io.File;
004: import java.io.FileInputStream;
005: import java.io.IOException;
006: import java.io.OutputStream;
007: import java.util.zip.Deflater;
008: import java.util.zip.ZipEntry;
009: import java.util.zip.ZipOutputStream;
010: import com.ice.util.Globber;
011:
012: /**
013: * This class provides the methods necessary to allow the
014: * download of working directory files and directories as
015: * ZIP archives.
016: *
017: * @author Tim Endres, <a href="mailto:time@gjt.org">time@gjt.org</a>
018: * @see com.ice.cvsc
019: */
020:
021: public class ZipHelper {
022: public ZipHelper() {
023: }
024:
025: public void writeZipArchive(OutputStream os, String rootName,
026: File zipDir, File rootDir, Globber match, Globber avoid)
027: throws IOException {
028: ZipOutputStream zos = new ZipOutputStream(os);
029:
030: zos.setLevel(Deflater.BEST_COMPRESSION);
031: zos.setMethod(ZipOutputStream.DEFLATED);
032: zos.setComment("Generated by JCVSWeb, <http://www.jcvs.org/>.");
033:
034: ZipEntry ze;
035:
036: ze = new ZipEntry(rootName + "/");
037: ze.setTime(zipDir.lastModified());
038: zos.putNextEntry(ze);
039: zos.closeEntry();
040:
041: this
042: .addZipEntries(zos, rootName, zipDir, rootDir, match,
043: avoid);
044:
045: zos.close();
046: }
047:
048: private void addZipEntries(ZipOutputStream zos, String rootName,
049: File dir, File rootDir, Globber match, Globber avoid)
050: throws IOException {
051: int len;
052: ZipEntry ze;
053: byte[] buf = new byte[16 * 1024];
054:
055: // This check lets us include all directories with,
056: // say class files, and no others... We may need a
057: // flag to turn this off?
058:
059: if (match != null)
060: if (!this .hasMatchingFiles(dir, match))
061: return;
062:
063: // We only add entries for subdirectories, as
064: // we assume the root entry has already been written.
065: if (!rootDir.equals(dir)) {
066: ze = new ZipEntry(this .getZipName(rootName, dir, rootDir));
067: ze.setTime(dir.lastModified());
068: zos.putNextEntry(ze);
069: zos.closeEntry();
070: }
071:
072: String[] files = dir.list();
073:
074: for (int i = 0; i < files.length; ++i) {
075: File f = new File(dir, files[i]);
076:
077: if (f.isDirectory()) {
078: // We do not want to include the CVS admin directories...
079: if (files[i].equals("CVS"))
080: continue;
081: } else {
082: // UNDONE
083: // REVIEW Should I apply these to directories?
084: if (avoid != null && avoid.isFileMatched(files[i]))
085: continue;
086:
087: if (match != null && !match.isFileMatched(files[i]))
088: continue;
089: }
090:
091: if (f.isDirectory()) {
092: // REVIEW Should we be adding directory ZipEntry's?
093: this .addZipEntries(zos, rootName, f, rootDir, match,
094: avoid);
095: } else {
096: FileInputStream ins = new FileInputStream(f);
097:
098: ze = new ZipEntry(this .getZipName(rootName, f, rootDir));
099:
100: ze.setTime(f.lastModified());
101: ze.setMethod(ZipEntry.DEFLATED);
102: ze
103: .setComment("Package '"
104: + rootName
105: + "' Build Path '"
106: + f.getCanonicalPath()
107: + "' "
108: + "Built by the jCVS Servlet "
109: + "com.ice.jcvslet.JCVSlet. <http://www.jcvs.org/>");
110:
111: zos.putNextEntry(ze);
112:
113: for (; (len = ins.read(buf)) >= 0;) {
114: zos.write(buf, 0, len);
115: }
116:
117: zos.closeEntry();
118: ins.close();
119: }
120: }
121: }
122:
123: private String getZipName(String rootName, File f, File rootDir)
124: throws IOException {
125: String path = f.getCanonicalPath();
126: String root = rootDir.getCanonicalPath();
127: String relPath = path.substring(root.length() + 1).replace(
128: File.separatorChar, '/');
129:
130: if (f.isDirectory())
131: if (!relPath.endsWith("/"))
132: relPath = relPath + "/";
133:
134: return rootName + "/" + relPath;
135: }
136:
137: private boolean hasMatchingFiles(File dir, Globber glob) {
138: // UNDONE We should use Hashtable caching for performance!!!!
139:
140: String[] files = dir.list();
141:
142: for (int i = 0; i < files.length; ++i) {
143: File f = new File(dir, files[i]);
144: if (f.isDirectory()) {
145: if (this .hasMatchingFiles(f, glob))
146: return true;
147: } else {
148: if (glob.isFileMatched(files[i]))
149: return true;
150: }
151: }
152:
153: return false;
154: }
155:
156: }
|