blob: a0bdf9ba754d66eb78c0225d15d08b11cf46a69a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 WARRANTIESOR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.aries.util.filesystem.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.aries.util.IORuntimeException;
import org.apache.aries.util.filesystem.ICloseableDirectory;
import org.apache.aries.util.filesystem.IDirectory;
import org.apache.aries.util.filesystem.IFile;
/**
* A directory in the zip.
*/
public class ZipDirectory extends ZipFileImpl implements IDirectory
{
/** The root of the zip FS. */
private final IDirectory root;
private final boolean zipRoot;
/**
* Constructs a directory in the zip.
*
* @param zip1 the zip file.
* @param entry1 the entry in the zip representing this dir.
* @param parent the parent directory.
*/
public ZipDirectory(File zip1, ZipEntry entry1, ZipDirectory parent, ZipCloseableDirectory cache)
{
super(zip1, entry1, parent, cache);
zipRoot = false;
root = parent.getRoot();
}
/**
* This constructor creates the root of the zip.
* @param fs
* @param parent
* @throws MalformedURLException
*/
public ZipDirectory(File fs, IDirectory parent) throws MalformedURLException
{
super(fs, parent);
root = (parent == null) ? this : parent.getRoot();
zipRoot = true;
}
public ZipDirectory(ZipDirectory other, ZipCloseableDirectory cache) {
super(other, cache);
root = other.root;
zipRoot = other.zipRoot;
}
public IFile getFile(String name)
{
IFile result = null;
String entryName = isZipRoot() ? name : getNameInZip() + "/" + name;
ZipEntry entryFile = getEntry(entryName);
if (entryFile != null) {
if (!!!entryFile.isDirectory()) {
result = new ZipFileImpl(zip, entryFile, buildParent(entryFile), cache);
} else {
result = new ZipDirectory(zip, entryFile, buildParent(entryFile), cache);
}
}
return result;
}
/**
* This method builds the parent directory hierarchy for a file.
* @param foundEntry
* @return the parent of the entry.
*/
private ZipDirectory buildParent(ZipEntry foundEntry)
{
ZipDirectory result = this;
String name = foundEntry.getName();
name = name.substring(getNameInZip().length());
String[] paths = name.split("/");
StringBuilder baseBuilderCrapThingToGetRoundFindBugs = new StringBuilder(getNameInZip());
if (!!!isZipRoot()) baseBuilderCrapThingToGetRoundFindBugs.append('/');
// Build 'result' as a chain of ZipDirectories. This will only work if java.util.ZipFile recognises every
// directory in the chain as being a ZipEntry in its own right.
outer: if (paths != null && paths.length > 1) {
for (int i = 0; i < paths.length - 1; i++) {
String path = paths[i];
baseBuilderCrapThingToGetRoundFindBugs.append(path);
ZipEntry dirEntry = getEntry(baseBuilderCrapThingToGetRoundFindBugs.toString());
if (dirEntry == null) {
result = this;
break outer;
}
result = new ZipDirectory(zip, dirEntry, result, cache);
baseBuilderCrapThingToGetRoundFindBugs.append('/');
}
}
return result;
}
public boolean isRoot()
{
return getParent() == null;
}
public List<IFile> listFiles()
{
return listFiles(false);
}
public List<IFile> listAllFiles()
{
return listFiles(true);
}
private List<IFile> listFiles(boolean includeFilesInNestedSubdirs)
{
List<IFile> files = new ArrayList<IFile>();
ZipFile z = openZipFile();
List<? extends ZipEntry> entries = Collections.list(z.entries());
for (ZipEntry possibleEntry : entries) {
if (isInDir(getNameInZip(), possibleEntry, includeFilesInNestedSubdirs)) {
ZipDirectory parent = includeFilesInNestedSubdirs ? buildParent(possibleEntry) : this;
if (possibleEntry.isDirectory()) {
files.add(new ZipDirectory(zip, possibleEntry, parent, cache));
} else {
files.add(new ZipFileImpl(zip, possibleEntry, parent, cache));
}
}
}
closeZipFile(z);
return files;
}
/**
* This method works out if the provided entry is inside this directory. It
* returns false if it is not, or if it is in a sub-directory.
*
* @param parentDir
* @param possibleEntry
* @param allowSubDirs
* @return true if it is in this directory.
*/
protected static boolean isInDir(String parentDir, ZipEntry possibleEntry, boolean allowSubDirs)
{
boolean result;
String name = possibleEntry.getName();
if (name.endsWith("/")) name = name.substring(0, name.length() - 1);
result = (name.startsWith(parentDir) && !!!name.equals(parentDir) && (allowSubDirs || name.substring(parentDir.length() + 1).indexOf('/') == -1));
return result;
}
public Iterator<IFile> iterator()
{
return listFiles().iterator();
}
public IDirectory convert()
{
return this;
}
public boolean isDirectory()
{
return true;
}
public boolean isFile()
{
return false;
}
public InputStream open()
{
throw new UnsupportedOperationException();
}
public IDirectory getRoot()
{
return root;
}
public boolean isZipRoot() {
return zipRoot;
}
// Although we only delegate to our super class if we removed this Findbugs
// would correctly point out that we add fields in this class, but do not
// take them into account for the equals method. In fact this is not a problem
// we do not care about the root when doing an equality check, but by including
// an equals or hashCode in here we can clearly document that we did this
// on purpose. Hence this comment.
@Override
public boolean equals(Object other)
{
return super.equals(other);
}
@Override
public int hashCode()
{
return super.hashCode();
}
private ZipEntry getEntry(String entryName) {
ZipFile z = openZipFile();
ZipEntry entryFile = null;
if (z != null) {
entryFile = z.getEntry(entryName);
closeZipFile(z);
}
return entryFile;
}
public ICloseableDirectory toCloseable() {
try {
return new ZipCloseableDirectory(zip, this);
} catch (IOException e) {
throw new IORuntimeException("IOException opening zip file: " + this, e);
}
}
}