package net.sourceforge.javautil.common.io.impl;
import java.io.File;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import net.sourceforge.javautil.common.io.IVirtualArtifact;
import net.sourceforge.javautil.common.io.VirtualArtifactNotFoundException;
import net.sourceforge.javautil.common.io.IVirtualDirectory;
import net.sourceforge.javautil.common.io.VirtualDirectoryAbstract;
import net.sourceforge.javautil.common.io.IVirtualFile;
import net.sourceforge.javautil.common.io.IVirtualPath;
/**
* The base for zipped directories.
*
* @author elponderador
* @author $Author: ponderator $
* @version $Id: ZippedDirectoryAbstract.java 2297 2010-06-16 00:13:14Z ponderator $
*/
public abstract class ZippedDirectoryAbstract extends VirtualDirectoryAbstract {
protected final ZippedDirectoryAbstract owner;
protected final IVirtualPath path;
protected final String name;
protected final Set<String> directories = new LinkedHashSet<String>();
protected final Set<String> files = new LinkedHashSet<String>();
protected boolean scanned = false;
public ZippedDirectoryAbstract(ZippedDirectoryAbstract owner, IVirtualPath path, String name) {
this.owner = owner;
this.path = path;
this.name = name;
}
public boolean isReadOnly() { return true; }
public void rename(String newName) { throw new UnsupportedOperationException("Cannot modify zip directories"); }
public IVirtualDirectory createDirectory(String name) { throw new UnsupportedOperationException("Cannot modify zip directories"); }
public IVirtualFile createFile(String name) { throw new UnsupportedOperationException("Cannot modify zip directories"); }
public boolean remove(String name) { throw new UnsupportedOperationException("Cannot modify zip directories"); }
public IVirtualArtifact getArtifact(String name) {
this.scan();
if (this.files.contains(name)) return new ZippedFile(getZipEntry(name), name, this);
if (this.directories.contains(name)) return new ZippedInternalDirectory(this, path.append(name));
return null;
}
public Iterator<IVirtualArtifact> getArtifacts() {
this.scan();
List<IVirtualArtifact> artifacts = new ArrayList<IVirtualArtifact>();
for (String directory : this.directories)
artifacts.add( this.getDirectory(directory) );
for (String file : this.files)
artifacts.add( this.getFile(file) );
return artifacts.iterator();
}
@Override public IVirtualPath getPath() { return path; }
public long getLength() { this.scan(); return this.directories.size() + this.files.size(); }
public IVirtualDirectory getOwner() { return null; }
public boolean makeDirectories() { return true; }
public boolean makeDirectory() { return true; }
public long getLastModified() { return getRealFile().getLastModified(); }
public String getName() { return name; }
public URL getURL() { return getRealFile().getURL(); }
public boolean isExists() { return getRealFile().isExists(); }
/**
* @param directory The directory to decompress this directory to
*/
public void decompress (IVirtualDirectory directory) {
this.scan();
for (String name : this.files) {
this.getFile(name).copy(directory);
}
for (String subdir : this.directories) {
IVirtualDirectory newdir = directory.getDirectory(subdir);
if (newdir == null) newdir = directory.createDirectory(subdir);
((ZippedDirectoryAbstract)this.getDirectory(subdir)).decompress(newdir);
}
}
/**
* @param path The path for which to get an internal directory
* @return A wrapper for the internally zipped directory
*/
protected ZippedInternalDirectory getInternalDirectory (IVirtualPath path) {
return new ZippedInternalDirectory(this, path);
}
/**
* @param name The name of an entry in this directory
* @return The zip entry corresponding to the name
*/
protected ZipEntry getZipEntry (String name) {
return getZipFile().getEntry(getPath().append(name).toString("/"));
}
/**
* @return The real system artifact behind this zipped directory
*/
protected abstract SystemFile getRealFile ();
/**
* @return The zip file wrapping the real file
*/
protected abstract ZipFile getZipFile ();
/**
* @return The list of entries
*/
protected abstract List<ZipEntry> getEntries ();
/**
* This happens once to determine which entries belong to this directory
*/
private void scan () {
if (this.scanned) return;
this.scanned = true;
String path = "".equals(this.name) ? "" : this.path.toString("/") + "/";
int partCount = this.path.getPartCount() + 1;
for (ZipEntry entry : this.getEntries()) {
if (entry.getName().startsWith(path)) {
IVirtualPath entryPath = new SimplePath(entry.getName());
if ( (entryPath.getPartCount() == partCount && entry.getName().endsWith("/"))) {
String name = entryPath.getPart(partCount-1);
if (!this.directories.contains(name)) this.directories.add(name);
continue;
}
IVirtualPath relativePath = entryPath.getPartCount() > partCount - 1 ? this.path.getRelativePath(entryPath) : entryPath;
if (entryPath.getPartCount() > partCount && relativePath.getPartCount() > 0) {
String name = relativePath.getPart(0);
if (!this.directories.contains(name)) this.directories.add(name);
} else if (entryPath.getPartCount() == partCount) {
this.files.add(entryPath.getPart(partCount-1));
}
}
}
}
}