/* * Copyright (c) 2016 OBiBa. All rights reserved. * * This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.obiba.core.util; import de.idyl.winzipaes.AesZipFileEncrypter; import de.idyl.winzipaes.impl.AESEncrypterBC; import java.io.*; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipOutputStream; public class ZipBuilder { private final File output; private final ZipOutputStream outputStream; private int baseLength = 0; private String password = ""; private AESEncrypterBC encrypter; private ZipBuilder(File output) throws FileNotFoundException { this.output = output; this.outputStream = new ZipOutputStream(new FileOutputStream(output)); } /** * Prepare a zip file at the given location. * * @param output output file * @return * @throws FileNotFoundException */ public static ZipBuilder newBuilder(File output) throws FileNotFoundException { return new ZipBuilder(output); } /** * Rebase the files relatively to the provided file. * * @param base base file * @return */ public ZipBuilder base(File base) { String path = (base.isDirectory() ? base : base.getParentFile()).getAbsolutePath(); if (!path.endsWith(File.separator)) { path = path + File.separator; } baseLength = path.length(); return this; } /** * Encrypt files with a password. * * @param password encryption password * @return * @throws ZipException */ public ZipBuilder password(String password) throws ZipException { this.password = password; if (hasPassword()) { this.encrypter = new AESEncrypterBC(); this.encrypter.init(password, 0); } return this; } /** * Apply best compression level. * * @return */ public ZipBuilder compressed() { outputStream.setLevel(Deflater.BEST_COMPRESSION); return this; } /** * Zip file or folder (recursively) without file filter. * * @param entry zip entry * @return * @throws IOException */ public ZipBuilder put(File entry) throws IOException { return put(entry, null); } /** * Zip file or folder (recursively) with file filter. * * @param entry zip entry * @param filter file filter * @return * @throws IOException */ public ZipBuilder put(File entry, FileFilter filter) throws IOException { if (entry.isDirectory()) { outputStream.putNextEntry(new ZipEntry(entry.getAbsolutePath().substring(baseLength) + "/")); File[] children = filter == null ? entry.listFiles() : entry.listFiles(filter); if (children != null) { for (File child : children) { put(child, filter); } } } else { outputStream.putNextEntry(new ZipEntry(entry.getAbsolutePath().substring(baseLength))); try(FileInputStream inputStream = new FileInputStream(entry)) { StreamUtil.copy(inputStream, outputStream); outputStream.closeEntry(); } } return this; } /** * Get the zip file, encrypt it if a password was provided. * * @return * @throws IOException */ public File build() throws IOException { outputStream.close(); if (hasPassword()) { File tmp = File.createTempFile(output.getName(), ".zip"); FileUtil.copyFile(output, tmp); output.delete(); AesZipFileEncrypter.zipAndEncryptAll(tmp, output, password, encrypter); tmp.delete(); } return output; } /** * Check if a password is provided. * * @return */ private boolean hasPassword() { return password != null && password.length()>0; } }