/*
* Copyright 2006,2007 Wilfred Springer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agilejava.maven.docbkx;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.IOUtils;
/**
* A mechanism for accessing the contents of zip files. The
* {@link #process(com.agilejava.maven.docbkx.ZipFileProcessor.ZipEntryVisitor)}
* operation accepts a {@link ZipFileProcessor.ZipEntryVisitor ZipEntryVisitor}
* that will be notified of every entry encountered in the zip file. This will
* eventually allow us to send in a single compound visitor executing several
* actions based on the entries encountered.
*
*
* @author Wilfred Springer
*
*/
public class ZipFileProcessor {
/**
* The zip file wrapped.
*/
private File file;
/**
* Constructs a new instance, wrapping the <code>file</code> passed in.
*
* @param file
* The zip file wrapped by this object.
*/
public ZipFileProcessor(File file) {
this.file = file;
}
/**
* Processes the contents of the zip file by processing all zip file entries
* in sequence and calling
* {@link ZipFileProcessor.ZipEntryVisitor#visit(ZipEntry, InputStream)} for
* every zip file entry encountered.
*
* @param visitor
* The visitor receiving the events.
* @throws IOException
* If it turned out to be impossible to read entries from the
* zip file passed in.
*/
public void process(ZipEntryVisitor visitor) throws IOException {
InputStream in = null;
ZipInputStream zipIn = null;
try {
in = new FileInputStream(file);
in = new BufferedInputStream(in);
zipIn = new ZipInputStream(in);
ZipEntry entry = null;
while ((entry = zipIn.getNextEntry()) != null) {
visitor.visit(entry, new SafeZipEntryInputStream(entry, zipIn));
}
} finally {
IOUtils.closeQuietly(zipIn);
IOUtils.closeQuietly(in);
}
}
/**
* The interface to be implemented by all objects that want to be notified
* of entries in a zip file.
*
*/
public interface ZipEntryVisitor {
/**
* Notifies the visitor of a zip file entry encoutered.
*
* @param entry
* The {@link ZipEntry} detected.
* @param in
* An {@link InputStream} allowing you to read directly the
* decompressed data from the zip entry.
* @throws IOException
* When the visitor fails to read from the
* <code>InputStream</code>.
*/
void visit(ZipEntry entry, InputStream in) throws IOException;
}
/**
* An {@link InputStream} wrapping a ZipInputStream preventing you from
* reading beyond the end of the zip entry.
*/
private static class SafeZipEntryInputStream extends InputStream {
/**
* The current position.
*/
private int pos = 0;
/**
* The size of the entry.
*/
private long size;
/**
* The {@link ZipInputStream} providing the data.
*/
private ZipInputStream in;
/**
* Constructs a new instance.
*
* @param entry The {@link ZipEntry} allowing you to access the details of the compressed zip entry.
* @param in An <code>InputStream</code> providing <em>direct</em> access to the zip file entry.
*/
public SafeZipEntryInputStream(ZipEntry entry, ZipInputStream in) {
size = entry.getCompressedSize();
this.in = in;
}
// JavaDoc inherited
public int read() throws IOException {
if (pos >= size) {
return -1;
} else {
return in.read();
}
}
}
}