/*
* 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.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
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;
import org.apache.aries.util.io.IOUtils;
public class NestedZipDirectory extends NestedZipFile implements IDirectory {
public NestedZipDirectory(IFile archive, ZipEntry entry, NestedZipDirectory parent, NestedCloseableDirectory cache) {
super(archive, entry, parent, cache);
}
public NestedZipDirectory(IFile archive, String pathInZip, NestedZipDirectory parent, NestedCloseableDirectory cache) {
super(archive, pathInZip, parent, cache);
}
public NestedZipDirectory(IFile archive) {
super(archive);
}
public NestedZipDirectory(NestedZipDirectory other, NestedCloseableDirectory cache) {
super(other, cache);
}
public IDirectory convert() {
return this;
}
public Iterator<IFile> iterator() {
return listFiles().iterator();
}
public List<IFile> listFiles() {
return listFiles(false);
}
public List<IFile> listAllFiles() {
return listFiles(true);
}
private List<IFile> listFiles(boolean includeFilesInNestedSubdirs) {
Map<String, ZipEntry> entriesByName = new LinkedHashMap<String, ZipEntry>();
for (ZipEntry entry : getAllEntries()) {
if (ZipDirectory.isInDir(getNameInZip(), entry, includeFilesInNestedSubdirs)) {
entriesByName.put(entry.getName(), entry);
}
}
List<IFile> files = new ArrayList<IFile>();
for (ZipEntry ze : entriesByName.values()) {
NestedZipDirectory parent = includeFilesInNestedSubdirs ? buildParent(ze, entriesByName) : this;
if (ze.isDirectory()) files.add(new NestedZipDirectory(archive, ze, parent, cache));
else files.add(new NestedZipFile(archive, ze, parent, cache));
}
return files;
}
private List<? extends ZipEntry> getAllEntries() {
if (cache != null && !!!cache.isClosed()) {
return Collections.list(cache.getZipFile().entries());
} else {
ZipInputStream zis = null;
try {
zis = new ZipInputStream(archive.open());
List<ZipEntry> result = new ArrayList<ZipEntry>();
ZipEntry entry = zis.getNextEntry();
while (entry != null) {
result.add(entry);
entry = zis.getNextEntry();
}
return result;
} catch (IOException e) {
throw new IORuntimeException("IOException reading nested ZipFile", e);
} finally {
IOUtils.close(zis);
}
}
}
private NestedZipDirectory buildParent(ZipEntry entry, Map<String,ZipEntry> entries) {
NestedZipDirectory result = this;
String path = entry.getName().substring(getNameInZip().length());
String[] segments = path.split("/");
if (segments != null && segments.length > 1) {
StringBuilder entryPath = new StringBuilder(getNameInZip());
for (int i=0; i<segments.length-1; i++) {
String p = segments[i];
entryPath.append(p).append("/");
ZipEntry ze = entries.get(entryPath.toString());
if (ze != null) {
result = new NestedZipDirectory(archive, ze, result, cache);
} else {
result = new NestedZipDirectory(archive, entryPath.toString(), result, cache);
}
}
}
return result;
}
public IFile getFile(String name) {
Map<String,ZipEntry> entries = new HashMap<String, ZipEntry>();
ZipEntry ze;
if (cache != null && !!!cache.isClosed()) {
ZipFile zip = cache.getZipFile();
String[] segments = name.split("/");
StringBuilder path = new StringBuilder();
for (String s : segments) {
path.append(s).append('/');
ZipEntry p = zip.getEntry(path.toString());
if (p != null) entries.put(path.toString(), p);
}
ze = zip.getEntry(name);
} else {
ZipInputStream zis = null;
try {
zis = new ZipInputStream(archive.open());
ze = zis.getNextEntry();
while (ze != null && !!!ze.getName().equals(name)) {
if (name.startsWith(ze.getName())) entries.put(ze.getName(), ze);
ze = zis.getNextEntry();
}
} catch (IOException e) {
throw new IORuntimeException("IOException reading nested ZipFile", e);
} finally {
IOUtils.close(zis);
}
}
if (ze != null) {
NestedZipDirectory parent = buildParent(ze, entries);
if (ze.isDirectory()) return new NestedZipDirectory(archive, ze, parent, cache);
else return new NestedZipFile(archive, ze, parent, cache);
} else {
return null;
}
}
public boolean isDirectory() {
return true;
}
public InputStream open() throws IOException, UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public boolean isFile() {
return false;
}
public boolean isRoot() {
return false;
}
public ICloseableDirectory toCloseable() {
try {
return new NestedCloseableDirectory(archive, this);
} catch (IOException e) {
throw new IORuntimeException("Exception while creating extracted version of nested zip file", e);
}
}
}