package com.openfarmanager.android.filesystem.actions;
import android.content.Context;
import com.github.junrar.Archive;
import com.openfarmanager.android.core.archive.ArchiveScanner;
import com.openfarmanager.android.core.archive.ArchiveUtils;
import com.openfarmanager.android.googledrive.model.exceptions.CreateFolderException;
import com.openfarmanager.android.model.TaskStatusEnum;
import com.openfarmanager.android.model.exeptions.SdcardPermissionException;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.model.FileHeader;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.zip.UnsupportedZipFeatureException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author Vlad Namashko
*/
public class ExtractArchiveTask extends FileActionTask {
private File mArchiveFile;
private File mDestinationFolder;
private ArchiveScanner.File mExtractTree;
private boolean mIsCompressed;
private String mEncryptedArchivePassword;
public ExtractArchiveTask(Context context, int forPanel, File archiveFile, File destination,
boolean compressed, String encryptedArchivePassword, ArchiveScanner.File extractTree) {
super(context, forPanel, new ArrayList<>());
mArchiveFile = archiveFile;
mDestinationFolder = destination;
mExtractTree = extractTree;
mIsCompressed = compressed;
mEncryptedArchivePassword = encryptedArchivePassword;
}
@Override
protected TaskStatusEnum doInBackground(Void... voids) {
if (mExtractTree == null) {
try {
ArchiveScanner.sInstance.clearArchive();
if (mEncryptedArchivePassword != null) { // another api for special case :(
ZipFile zipFile = new ZipFile(mArchiveFile);
zipFile.setPassword(mEncryptedArchivePassword);
// Get the list of file headers from the zip file
List fileHeaderList = zipFile.getFileHeaders();
// Loop through the file headers
for (Object aFileHeaderList : fileHeaderList) {
FileHeader fileHeader = (FileHeader) aFileHeaderList;
// Extract the file to the specified destination
ArchiveScanner.sInstance.root().processFile(fileHeader.getFileName(), fileHeader.getUncompressedSize());
}
} else if (ArchiveUtils.isRarArchive(mArchiveFile)) { // one more special case :(
Archive rarArchive = new Archive(mArchiveFile);
List<com.github.junrar.rarfile.FileHeader> fileHeaders = rarArchive.getFileHeaders();
for (final com.github.junrar.rarfile.FileHeader header : fileHeaders) {
if (header.isDirectory()) {
continue;
}
ArchiveScanner.sInstance.root().processFile(header.getFileNameString(), header.getFullUnpackSize());
}
} else if (ArchiveUtils.is7zArchive(mArchiveFile)) { // and one more special case :( :( :(
SevenZFile sevenZFile = new SevenZFile(mArchiveFile, mEncryptedArchivePassword == null ? null : mEncryptedArchivePassword.getBytes());
SevenZArchiveEntry entry = sevenZFile.getNextEntry();
while (entry != null) {
if (!entry.isDirectory()) {
ArchiveScanner.sInstance.root().processFile(entry.getName(), entry.getSize());
}
byte[] content = new byte[(int) entry.getSize()];
sevenZFile.read(content, 0, content.length);
entry = sevenZFile.getNextEntry();
}
sevenZFile.close();
} else {
ArchiveInputStream inputStream = ArchiveUtils.createInputStream(
mIsCompressed ?
new CompressorStreamFactory().createCompressorInputStream(new BufferedInputStream(new FileInputStream(mArchiveFile))) :
new FileInputStream(mArchiveFile)
);
ArchiveEntry entry;
while ((entry = inputStream.getNextEntry()) != null) {
ArchiveScanner.sInstance.root().processFile(entry.getName(), entry.getSize());
}
}
} catch (UnsupportedZipFeatureException e) {
return TaskStatusEnum.ERROR_EXTRACTING_ARCHIVE_FILES_ENCRYPTION_PASSWORD_REQUIRED;
} catch (IOException e) {
if (e.getMessage().equals("Cannot read encrypted files without a password")) {
return TaskStatusEnum.ERROR_EXTRACTING_ARCHIVE_FILES_ENCRYPTION_PASSWORD_REQUIRED;
} else {
return TaskStatusEnum.ERROR_CREATING_ARCHIVE_FILES_TREE;
}
} catch (CreateFolderException e) {
return TaskStatusEnum.ERROR_CAN_T_CREATE_DIRECTORY;
} catch (Exception e) {
return TaskStatusEnum.ERROR_CREATING_ARCHIVE_FILES_TREE;
}
mExtractTree = ArchiveScanner.sInstance.root();
}
try {
ArchiveUtils.extractArchive(mArchiveFile, mDestinationFolder, mExtractTree, mIsCompressed, mEncryptedArchivePassword, mListener);
} catch (SdcardPermissionException e) {
return TaskStatusEnum.ERROR_STORAGE_PERMISSION_REQUIRED;
} catch (Exception e) {
return TaskStatusEnum.ERROR_EXTRACTING_ARCHIVE_FILES;
}
return TaskStatusEnum.OK;
}
private ArchiveUtils.ExtractArchiveListener mListener = new ArchiveUtils.ExtractArchiveListener() {
@Override
public void beforeExtractStarted(int filesToExtract) {
mTotalSize = filesToExtract;
}
@Override
public void onFileExtracted(ArchiveScanner.File extractedFile) {
mTotalSize++;
updateProgress();
}
};
}