/*
* (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Nuxeo - initial API and implementation
*/
package org.nuxeo.common.utils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
/**
* @author bstefanescu
*/
public final class ZipUtils {
// This is an utility class
private ZipUtils() {
}
// _____________________________ ZIP ________________________________
public static void _putDirectoryEntry(String entryName, ZipOutputStream out) throws IOException {
ZipEntry zentry = new ZipEntry(entryName + '/');
out.putNextEntry(zentry);
out.closeEntry();
}
public static void _putFileEntry(File file, String entryName, ZipOutputStream out) throws IOException {
try (FileInputStream in = new FileInputStream(file)) {
_zip(entryName, in, out);
}
}
public static void _zip(String entryName, InputStream in, ZipOutputStream out) throws IOException {
ZipEntry zentry = new ZipEntry(entryName);
out.putNextEntry(zentry);
// Transfer bytes from the input stream to the ZIP file
IOUtils.copy(in, out);
out.closeEntry();
}
public static void _zip(String entryName, File file, ZipOutputStream out) throws IOException {
// System.out.println("Compressing "+entryName);
if (file.isDirectory()) {
entryName += '/';
ZipEntry zentry = new ZipEntry(entryName);
out.putNextEntry(zentry);
out.closeEntry();
File[] files = file.listFiles();
for (int i = 0, len = files.length; i < len; i++) {
_zip(entryName + files[i].getName(), files[i], out);
}
} else {
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
_zip(entryName, in, out);
} finally {
if (in != null) {
in.close();
}
}
}
}
public static void _zip(File[] files, ZipOutputStream out, String prefix) throws IOException {
if (prefix != null) {
int len = prefix.length();
if (len == 0) {
prefix = null;
} else if (prefix.charAt(len - 1) != '/') {
prefix += '/';
}
}
for (int i = 0, len = files.length; i < len; i++) {
String name = prefix != null ? prefix + files[i].getName() : files[i].getName();
_zip(name, files[i], out);
}
}
public static void zip(File file, OutputStream out, String prefix) throws IOException {
if (prefix != null) {
int len = prefix.length();
if (len == 0) {
prefix = null;
} else if (prefix.charAt(len - 1) != '/') {
prefix += '/';
}
}
String name = prefix != null ? prefix + file.getName() : file.getName();
try (ZipOutputStream zout = new ZipOutputStream(out)) {
_zip(name, file, zout);
}
}
public static void zip(File[] files, OutputStream out, String prefix) throws IOException {
try (ZipOutputStream zout = new ZipOutputStream(out)) {
_zip(files, zout, prefix);
}
}
public static void zip(File file, File zip) throws IOException {
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(zip))) {
zip(file, out, null);
}
}
public static void zip(File[] files, File zip) throws IOException {
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(zip))) {
zip(files, out, null);
}
}
public static void zip(File file, File zip, String prefix) throws IOException {
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(zip))) {
zip(file, out, prefix);
}
}
public static void zip(File[] files, File zip, String prefix) throws IOException {
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(zip))) {
zip(files, out, prefix);
}
}
public static void zipFilesUsingPrefix(String prefix, File[] files, OutputStream out) throws IOException {
try (ZipOutputStream zout = new ZipOutputStream(out)) {
if (prefix != null && prefix.length() > 0) {
int p = prefix.indexOf('/');
while (p > -1) {
_putDirectoryEntry(prefix.substring(0, p), zout);
p = prefix.indexOf(p + 1, '/');
}
_putDirectoryEntry(prefix, zout);
prefix += '/';
} else {
prefix = "";
}
// prefix = prefix + '/';
for (File file : files) {
_putFileEntry(file, prefix + file.getName(), zout);
}
}
}
// _____________________________ UNZIP ________________________________
public static void unzip(String prefix, InputStream zipStream, File dir) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(zipStream))) {
unzip(prefix, in, dir);
}
}
public static void unzip(InputStream zipStream, File dir) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(zipStream))) {
unzip(in, dir);
}
}
public static void unzip(String prefix, URL zip, File dir) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(zip.openStream()))) {
unzip(prefix, in, dir);
}
}
public static void unzip(URL zip, File dir) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(zip.openStream()))) {
unzip(in, dir);
}
}
public static void unzip(String prefix, File zip, File dir) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip)))) {
unzip(prefix, in, dir);
}
}
public static void unzip(File zip, File dir) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip)))) {
unzip(in, dir);
}
}
public static void unzip(String prefix, ZipInputStream in, File dir) throws IOException {
unzip(in, dir, entry -> entry.getName().startsWith(prefix), name -> name.substring(prefix.length()));
}
public static void unzip(ZipInputStream in, File dir) throws IOException {
unzip(in, dir, entry -> true, Function.identity());
}
private static void unzip(ZipInputStream in, File dir, Predicate<ZipEntry> filter,
Function<String, String> nameFormatter) throws IOException {
dir.mkdirs();
ZipEntry entry;
while ((entry = in.getNextEntry()) != null) {
if (!entry.getName().contains("..") && filter.test(entry)) {
File file = new File(dir, nameFormatter.apply(entry.getName()));
if (entry.isDirectory()) {
file.mkdirs();
} else {
file.getParentFile().mkdirs();
try (FileOutputStream output = FileUtils.openOutputStream(file)) {
IOUtils.copy(in, output);
}
}
}
}
}
public static void unzipIgnoreDirs(ZipInputStream in, File dir) throws IOException {
unzip(in, dir, entry -> !entry.isDirectory(), Function.identity());
}
public static void unzipIgnoreDirs(InputStream zipStream, File dir) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(zipStream))) {
unzipIgnoreDirs(in, dir);
}
}
public static void unzip(File zip, File dir, PathFilter filter) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip)))) {
unzip(in, dir, filter);
}
}
public static void unzip(ZipInputStream in, File dir, PathFilter filter) throws IOException {
if (filter == null) {
unzip(in, dir);
} else {
unzip(in, dir, toPredicate(filter), Function.identity());
}
}
public static void unzip(String prefix, File zip, File dir, PathFilter filter) throws IOException {
try (ZipInputStream in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip)))) {
unzip(prefix, in, dir, filter);
}
}
public static void unzip(String prefix, ZipInputStream in, File dir, PathFilter filter) throws IOException {
if (filter == null) {
unzip(prefix, in, dir);
} else {
unzip(in, dir, toPredicate(filter).and(entry -> entry.getName().startsWith(prefix)),
name -> name.substring(prefix.length()));
}
}
private static Predicate<ZipEntry> toPredicate(PathFilter filter) {
return entry -> filter.accept(new Path(entry.getName()));
}
// ________________ Entries ________________
/**
* Unzip directly the entry. The returned InputStream has to be closed.
*
* @return the input stream of the desired entry - has to be closed by the caller, or null if not found
* @param file the source file
* @param entryName the entry name that has to be extracted
*/
public static InputStream getEntryContentAsStream(File file, String entryName) throws IOException {
InputStream result = null;
ZipFile zip = new ZipFile(file);
ZipEntry entry = zip.getEntry(entryName);
if (entry != null) {
result = zip.getInputStream(entry);
}
return result;
}
/**
* Unzip directly the entry.
*
* @return the String content of the entry with name entryName
* @param file the source file
* @param entryName the entry name that has to be extracted
*/
public static String getEntryContentAsString(File file, String entryName) throws IOException {
try (InputStream resultStream = getEntryContentAsStream(file, entryName)) {
return IOUtils.toString(resultStream, Charsets.UTF_8);
}
}
/**
* Unzips directly the entry.
*
* @return The byte array content of the entry with name entryName
* @param file the source file
* @param entryName the entry name that has to be extracted
*/
public static byte[] getEntryContentAsBytes(File file, String entryName) throws IOException {
try (InputStream resultStream = getEntryContentAsStream(file, entryName)) {
return IOUtils.toByteArray(resultStream);
}
}
/**
* Lists the entries on the zip file.
*
* @param file The zip file
* @return The list of entries
*/
public static List<String> getEntryNames(File file) throws IOException {
List<String> result = new ArrayList<String>();
try (ZipFile zip = new ZipFile(file)) {
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
result.add(entry.getName());
}
}
return result;
}
/**
* Checks if a zip file contains a specified entry name.
*
* @param file the zip file
* @param entryName The content to be checked
* @return True if the file contains entryName. False otherwise
*/
public static boolean hasEntry(File file, String entryName) throws IOException {
List<String> elements = getEntryNames(file);
return elements.contains(entryName);
}
public static InputStream getEntryContentAsStream(InputStream stream, String entryName) throws IOException {
ZipInputStream zip = new ZipInputStream(stream);
ZipEntry entry = zip.getNextEntry();
while (entry != null) {
if (entry.getName().equals(entryName)) {
return zip;
}
entry = zip.getNextEntry();
}
return null;
}
public static String getEntryContentAsString(InputStream stream, String searchedEntryName) throws IOException {
try (InputStream resultStream = getEntryContentAsStream(stream, searchedEntryName)) {
return IOUtils.toString(resultStream, Charsets.UTF_8);
}
}
public static byte[] getEntryContentAsBytes(InputStream stream, String searchedEntryName) throws IOException {
try (InputStream resultStream = getEntryContentAsStream(stream, searchedEntryName)) {
return IOUtils.toByteArray(resultStream);
}
}
public static List<String> getEntryNames(InputStream stream) throws IOException {
List<String> result = new ArrayList<String>();
try (ZipInputStream zip = new ZipInputStream(stream)) {
while (zip.available() == 1) {
ZipEntry entry = zip.getNextEntry();
if (entry != null) {
result.add(entry.getName());
}
}
}
return result;
}
public static boolean hasEntry(InputStream stream, String entryName) throws IOException {
List<String> elements = getEntryNames(stream);
return elements.contains(entryName);
}
public static InputStream getEntryContentAsStream(URL url, String entryName) throws IOException {
return getEntryContentAsStream(url.openStream(), entryName);
}
public static String getEntryContentAsString(URL url, String entryName) throws IOException {
try (InputStream resultStream = getEntryContentAsStream(url, entryName)) {
return IOUtils.toString(resultStream, Charsets.UTF_8);
}
}
public static byte[] getEntryContentAsBytes(URL url, String entryName) throws IOException {
try (InputStream resultStream = getEntryContentAsStream(url, entryName)) {
return IOUtils.toByteArray(resultStream);
}
}
public static List<String> getEntryNames(URL url) throws IOException {
return getEntryNames(url.openStream());
}
public static boolean hasEntry(URL url, String entryName) throws IOException {
return hasEntry(url.openStream(), entryName);
}
}