use of com.mucommander.commons.file.archive.ArchiveEntryIterator in project mucommander by mucommander.
the class ZipArchiveFile method getEntryIterator.
// ////////////////////////////////////////
// AbstractROArchiveFile implementation //
// ////////////////////////////////////////
@Override
public synchronized ArchiveEntryIterator getEntryIterator() throws IOException, UnsupportedFileOperationException {
// If the underlying AbstractFile has random read access, use our own ZipFile implementation to read entries
if (file.isFileOperationSupported(FileOperation.RANDOM_READ_FILE)) {
checkZipFile();
final Iterator<ZipEntry> iterator = zipFile.getEntries();
return new ArchiveEntryIterator() {
@Override
public ArchiveEntry nextEntry() throws IOException {
ZipEntry entry;
if (!iterator.hasNext() || (entry = iterator.next()) == null)
return null;
return createArchiveEntry(entry);
}
};
} else // If the underlying AbstractFile doesn't have random read access, use java.util.zip.ZipInputStream to
// read the entries. This is much slower than the former method as the file cannot be sought through and needs
// to be traversed.
{
return new JavaUtilZipEntryIterator(new ZipInputStream(file.getInputStream()));
}
}
use of com.mucommander.commons.file.archive.ArchiveEntryIterator in project mucommander by mucommander.
the class UnpackJob method processFile.
/**
* Unpacks the given archive file. If the file is a directory, its children will be processed recursively.
* If the file is not an archive file nor a directory, it is not processed and <code>false</code> is returned.
*
* @param file the file to unpack
* @param recurseParams unused
* @return <code>true</code> if the file has been processed successfully
*/
@Override
protected boolean processFile(AbstractFile file, Object recurseParams) {
// Stop if interrupted
if (getState() == FileJobState.INTERRUPTED)
return false;
// Destination folder
AbstractFile destFolder = baseDestFolder;
// If the file is a directory, process its children recursively
if (file.isDirectory()) {
do {
// Loop for retries
try {
// List files inside archive file (can throw an IOException)
AbstractFile[] archiveFiles = getCurrentFile().ls();
// Recurse on zip's contents
for (int j = 0; j < archiveFiles.length && getState() != FileJobState.INTERRUPTED; j++) {
// Notify job that we're starting to process this file (needed for recursive calls to processFile)
nextFile(archiveFiles[j]);
// Recurse
processFile(archiveFiles[j], destFolder);
}
// Return true when complete
return true;
} catch (IOException e) {
// File could not be uncompressed properly
DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_read_file", getCurrentFilename()));
// Retry loops
if (ret == FileJobAction.RETRY)
continue;
// cancel, skip or close dialog will simply return false
return false;
}
} while (true);
}
// Abort if the file is neither an archive file nor a directory
if (!file.isArchive())
return false;
// 'Cast' the file as an archive file
AbstractArchiveFile archiveFile = file.getAncestor(AbstractArchiveFile.class);
String destSeparator = destFolder.getSeparator();
// Unpack the archive, copying entries one by one, in the iterator's order
try (ArchiveEntryIterator iterator = archiveFile.getEntryIterator()) {
ArchiveEntry entry;
while ((entry = iterator.nextEntry()) != null && getState() != FileJobState.INTERRUPTED) {
String entryPath = entry.getPath();
boolean processEntry = false;
if (selectedEntries == null) {
// Entries are processed
processEntry = true;
} else {
// We need to determine if the entry should be processed or not
// Process this entry if the selectedEntries set contains this entry, or a parent of this entry
int nbSelectedEntries = selectedEntries.size();
for (int i = 0; i < nbSelectedEntries; i++) {
ArchiveEntry selectedEntry = selectedEntries.get(i);
// selectedEntry is a parent of the current entry.
if (selectedEntry.isDirectory()) {
if (entryPath.startsWith(selectedEntry.getPath())) {
processEntry = true;
break;
// Note: we can't remove selectedEntryPath from the set, we still need it
}
} else if (entryPath.equals(selectedEntry.getPath())) {
// If the (regular file) entry is in the set, remove it as we no longer need it (will speed up
// subsequent searches)
processEntry = true;
selectedEntries.remove(i);
break;
}
}
}
if (!processEntry)
continue;
DefaultMutableTreeNode entryNode = archiveFile.getArchiveEntryNode(entryPath);
if (entryNode != null) {
ArchiveEntry archiveEntry = (ArchiveEntry) entryNode.getUserObject();
if (archiveEntry.isSymbolicLink()) {
Files.createSymbolicLink(FileSystems.getDefault().getPath(destFolder.getPath(), entry.getName()), FileSystems.getDefault().getPath(entry.getLinkTarget()));
continue;
}
}
// Resolve the entry file
AbstractFile entryFile = archiveFile.getArchiveEntryFile(entryPath);
// Notify the job that we're starting to process this file
nextFile(entryFile);
// Figure out the destination file's path, relatively to the base destination folder
String relDestPath = baseArchiveDepth == 0 ? entry.getPath() : PathUtils.removeLeadingFragments(entry.getPath(), "/", baseArchiveDepth);
if (newName != null)
relDestPath = newName + (PathUtils.getDepth(relDestPath, "/") <= 1 ? "" : "/" + PathUtils.removeLeadingFragments(relDestPath, "/", 1));
if (!"/".equals(destSeparator))
relDestPath = relDestPath.replace("/", destSeparator);
// Create destination AbstractFile instance
AbstractFile destFile = destFolder.getChild(relDestPath);
// Check for ZipSlip (see https://snyk.io/research/zip-slip-vulnerability)
do {
if (destFolder.isParentOf(destFile))
break;
DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("unpack.entry_out_of_target_dir", destFile.getName()));
// Retry loops
if (ret == FileJobAction.RETRY)
continue;
// Cancel, skip or close dialog returns false
return false;
} while (true);
// Check if the file does not already exist in the destination
destFile = checkForCollision(entryFile, destFolder, destFile, false);
if (destFile == null) {
// A collision occurred and either the file was skipped, or the user cancelled the job
continue;
}
// If the entry is a directory ...
if (entryFile.isDirectory()) {
// Create the directory in the destination, if it doesn't already exist
if (!(destFile.exists() && destFile.isDirectory())) {
// Loop for retry
do {
try {
// Use mkdirs() instead of mkdir() to create any parent folder that doesn't exist yet
destFile.mkdirs();
} catch (IOException e) {
// Unable to create folder
DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_create_folder", entryFile.getName()));
// Retry loops
if (ret == FileJobAction.RETRY)
continue;
// Cancel or close dialog return false
return false;
// Skip continues
}
break;
} while (true);
}
} else // The entry is a regular file, copy it
{
// Create the file's parent directory(s) if it doesn't already exist
AbstractFile destParentFile = destFile.getParent();
if (!destParentFile.exists()) {
// Use mkdirs() instead of mkdir() to create any parent folder that doesn't exist yet
destParentFile.mkdirs();
}
// some archive file implementations (such as TAR) can speed things by an order of magnitude.
if (!tryCopyFile(new ProxiedEntryFile(entryFile, entry, archiveFile, iterator), destFile, append, errorDialogTitle))
return false;
}
}
return true;
} catch (IOException e) {
showErrorDialog(errorDialogTitle, Translator.get("cannot_read_file", archiveFile.getName()));
}
return false;
}
use of com.mucommander.commons.file.archive.ArchiveEntryIterator in project mucommander by mucommander.
the class ArArchiveFile method getEntryInputStream.
@Override
public InputStream getEntryInputStream(ArchiveEntry entry, ArchiveEntryIterator entryIterator) throws IOException, UnsupportedFileOperationException {
InputStream in = getInputStream();
ArchiveEntryIterator iterator = new ArArchiveEntryIterator(in);
ArchiveEntry currentEntry;
while ((currentEntry = iterator.nextEntry()) != null) {
if (currentEntry.getName().equals(entry.getName())) {
LOGGER.trace("found entry {}", entry.getName());
return new BoundedInputStream(in, entry.getSize(), false);
}
}
// Entry not found, should not normally happen
LOGGER.info("Warning: entry not found, throwing IOException");
throw new IOException();
}
Aggregations