/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2016 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://developer.catrobat.org/license_additional_term
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.catroid.utils;
import android.util.Log;
import org.catrobat.catroid.common.Constants;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public final class UtilZip {
private static final int QUICKEST_COMPRESSION = 0;
private static final String TAG = UtilZip.class.getSimpleName();
private static final String DIRECTORY_LEVEL_UP = "../";
private static final String ERROR_FOLDER_NOT_CREATED = "Folder not created";
private static final String ERROR_CLOSING_STREAM = "Error closing stream";
private static ZipOutputStream zipOutputStream;
// Suppress default constructor for noninstantiability
private UtilZip() {
throw new AssertionError();
}
public static boolean writeToZipFile(String[] filePaths, String zipFile) {
try {
FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
zipOutputStream = new ZipOutputStream(fileOutputStream);
zipOutputStream.setLevel(QUICKEST_COMPRESSION);
for (String filePath : filePaths) {
File file = new File(filePath);
if (file.isDirectory()) {
writeDirToZip(file, file.getName() + "/");
} else {
writeFileToZip(file, "");
}
}
return true;
} catch (IOException ioException) {
Log.e(TAG, ioException.getMessage(), ioException);
} finally {
try {
if (zipOutputStream != null) {
zipOutputStream.close();
}
} catch (IOException ignoredException) {
Log.e(TAG, ERROR_CLOSING_STREAM, ignoredException);
}
}
return false;
}
private static void writeDirToZip(File dir, String zipEntryPath) throws IOException {
for (String dirListEntry : dir.list()) {
File file = new File(dir, dirListEntry);
if (file.isDirectory()) {
writeDirToZip(file, zipEntryPath + file.getName() + "/");
continue;
}
writeFileToZip(file, zipEntryPath);
}
}
private static void writeFileToZip(File file, String zipEntryPath) throws IOException {
byte[] readBuffer = new byte[Constants.BUFFER_8K];
int bytesIn;
FileInputStream fileInputStream = new FileInputStream(file);
ZipEntry zipEntry = new ZipEntry(zipEntryPath + file.getName());
zipOutputStream.putNextEntry(zipEntry);
while ((bytesIn = fileInputStream.read(readBuffer)) != -1) {
zipOutputStream.write(readBuffer, 0, bytesIn);
}
zipOutputStream.closeEntry();
fileInputStream.close();
}
public static boolean unZipFile(String zipFileName, String outDirectory) {
File file;
BufferedOutputStream destinationOutputStream = null;
ZipInputStream zipInputStream = null;
try {
byte[] data = new byte[Constants.BUFFER_8K];
file = new File(zipFileName);
zipInputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
if (zipEntry.getName().contains(DIRECTORY_LEVEL_UP)) {
Log.d(TAG, "Path traversal attack prevented");
continue;
}
if (zipEntry.isDirectory()) {
File entryFile = new File(Utils.buildPath(outDirectory, zipEntry.getName()));
if (!entryFile.mkdirs() && !entryFile.isDirectory()) {
zipInputStream.close();
throw new IOException(ERROR_FOLDER_NOT_CREATED);
}
continue;
}
File entryFile = new File(Utils.buildPath(outDirectory, zipEntry.getName()));
if (!entryFile.getParentFile().mkdirs() && !entryFile.getParentFile().isDirectory()) {
zipInputStream.close();
throw new IOException(ERROR_FOLDER_NOT_CREATED);
}
FileOutputStream fileOutputStream = new FileOutputStream(entryFile);
int count;
destinationOutputStream = new BufferedOutputStream(fileOutputStream, Constants.BUFFER_8K);
while ((count = zipInputStream.read(data, 0, Constants.BUFFER_8K)) > 0) {
destinationOutputStream.write(data, 0, count);
}
destinationOutputStream.flush();
}
return true;
} catch (FileNotFoundException fileNotFoundException) {
Log.e(TAG, fileNotFoundException.getMessage(), fileNotFoundException);
} catch (IOException ioException) {
Log.e(TAG, ioException.getMessage(), ioException);
} finally {
try {
if (destinationOutputStream != null) {
destinationOutputStream.close();
}
if (zipInputStream != null) {
zipInputStream.close();
}
} catch (IOException ignoredException) {
Log.e(TAG, ERROR_CLOSING_STREAM, ignoredException);
}
}
return false;
}
public static void deleteZipFile(String fileName, String destinationFolder) {
File fileToBeDeleted = new File(destinationFolder, fileName);
if (fileToBeDeleted.exists()) {
fileToBeDeleted.delete();
}
}
}