/*
* Copyright 2010 Srikanth Reddy Lingala
*
* 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.
*/
package net.lingala.zip4j.unzip;
import java.io.File;
import java.util.ArrayList;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.ZipInputStream;
import net.lingala.zip4j.model.CentralDirectory;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.UnzipParameters;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.Zip4jUtil;
public class Unzip {
private ZipModel zipModel;
public Unzip(ZipModel zipModel) throws ZipException {
if (zipModel == null) {
throw new ZipException("ZipModel is null");
}
this.zipModel = zipModel;
}
public void extractAll(final UnzipParameters unzipParameters, final String outPath,
final ProgressMonitor progressMonitor, boolean runInThread) throws ZipException {
CentralDirectory centralDirectory = zipModel.getCentralDirectory();
if (centralDirectory == null ||
centralDirectory.getFileHeaders() == null) {
throw new ZipException("invalid central directory in zipModel");
}
final ArrayList fileHeaders = centralDirectory.getFileHeaders();
progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_EXTRACT);
progressMonitor.setTotalWork(calculateTotalWork(fileHeaders));
progressMonitor.setState(ProgressMonitor.STATE_BUSY);
if (runInThread) {
Thread thread = new Thread(InternalZipConstants.THREAD_NAME) {
public void run() {
try {
initExtractAll(fileHeaders, unzipParameters, progressMonitor, outPath);
progressMonitor.endProgressMonitorSuccess();
} catch (ZipException e) {
}
}
};
thread.start();
} else {
initExtractAll(fileHeaders, unzipParameters, progressMonitor, outPath);
}
}
private void initExtractAll(ArrayList fileHeaders, UnzipParameters unzipParameters,
ProgressMonitor progressMonitor, String outPath) throws ZipException {
for (int i = 0; i < fileHeaders.size(); i++) {
FileHeader fileHeader = (FileHeader)fileHeaders.get(i);
initExtractFile(fileHeader, outPath, unzipParameters, null, progressMonitor);
if (progressMonitor.isCancelAllTasks()) {
progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
progressMonitor.setState(ProgressMonitor.STATE_READY);
return;
}
}
}
public void extractFile(final FileHeader fileHeader, final String outPath,
final UnzipParameters unzipParameters, final String newFileName,
final ProgressMonitor progressMonitor, boolean runInThread) throws ZipException {
if (fileHeader == null) {
throw new ZipException("fileHeader is null");
}
progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_EXTRACT);
progressMonitor.setTotalWork(fileHeader.getCompressedSize());
progressMonitor.setState(ProgressMonitor.STATE_BUSY);
progressMonitor.setPercentDone(0);
progressMonitor.setFileName(fileHeader.getFileName());
if (runInThread) {
Thread thread = new Thread(InternalZipConstants.THREAD_NAME) {
public void run() {
try {
initExtractFile(fileHeader, outPath, unzipParameters, newFileName, progressMonitor);
progressMonitor.endProgressMonitorSuccess();
} catch (ZipException e) {
}
}
};
thread.start();
} else {
initExtractFile(fileHeader, outPath, unzipParameters, newFileName, progressMonitor);
progressMonitor.endProgressMonitorSuccess();
}
}
private void initExtractFile(FileHeader fileHeader, String outPath,
UnzipParameters unzipParameters, String newFileName, ProgressMonitor progressMonitor) throws ZipException {
if (fileHeader == null) {
throw new ZipException("fileHeader is null");
}
try {
progressMonitor.setFileName(fileHeader.getFileName());
if (!outPath.endsWith(InternalZipConstants.FILE_SEPARATOR)) {
outPath += InternalZipConstants.FILE_SEPARATOR;
}
// If file header is a directory, then check if the directory exists
// If not then create a directory and return
if (fileHeader.isDirectory()) {
try {
String fileName = fileHeader.getFileName();
if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileName)) {
return;
}
String completePath = outPath + fileName;
File file = new File(completePath);
if (!file.exists()) {
file.mkdirs();
}
} catch (Exception e) {
progressMonitor.endProgressMonitorError(e);
throw new ZipException(e);
}
} else {
//Create Directories
checkOutputDirectoryStructure(fileHeader, outPath, newFileName);
UnzipEngine unzipEngine = new UnzipEngine(zipModel, fileHeader);
try {
unzipEngine.unzipFile(progressMonitor, outPath, newFileName, unzipParameters);
} catch (Exception e) {
progressMonitor.endProgressMonitorError(e);
throw new ZipException(e);
}
}
} catch (ZipException e) {
progressMonitor.endProgressMonitorError(e);
throw e;
} catch (Exception e) {
progressMonitor.endProgressMonitorError(e);
throw new ZipException(e);
}
}
public ZipInputStream getInputStream(FileHeader fileHeader) throws ZipException {
UnzipEngine unzipEngine = new UnzipEngine(zipModel, fileHeader);
return unzipEngine.getInputStream();
}
private void checkOutputDirectoryStructure(FileHeader fileHeader, String outPath, String newFileName) throws ZipException {
if (fileHeader == null || !Zip4jUtil.isStringNotNullAndNotEmpty(outPath)) {
throw new ZipException("Cannot check output directory structure...one of the parameters was null");
}
String fileName = fileHeader.getFileName();
if (Zip4jUtil.isStringNotNullAndNotEmpty(newFileName)) {
fileName = newFileName;
}
if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileName)) {
// Do nothing
return;
}
String compOutPath = outPath + fileName;
try {
File file = new File(compOutPath);
String parentDir = file.getParent();
File parentDirFile = new File(parentDir);
if (!parentDirFile.exists()) {
parentDirFile.mkdirs();
}
} catch (Exception e) {
throw new ZipException(e);
}
}
private long calculateTotalWork(ArrayList fileHeaders) throws ZipException {
if (fileHeaders == null) {
throw new ZipException("fileHeaders is null, cannot calculate total work");
}
long totalWork = 0;
for (int i = 0; i < fileHeaders.size(); i++) {
FileHeader fileHeader = (FileHeader)fileHeaders.get(i);
if (fileHeader.getZip64ExtendedInfo() != null &&
fileHeader.getZip64ExtendedInfo().getUnCompressedSize() > 0) {
totalWork += fileHeader.getZip64ExtendedInfo().getCompressedSize();
} else {
totalWork += fileHeader.getCompressedSize();
}
}
return totalWork;
}
}