Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 46a0da8e authored by François Degros's avatar François Degros
Browse files

Ensure that ArchiveHandle.getInputStream() cannot return null

Simplify ArchiveEntryInputStream.create() by using more modern Java
constructs. This makes the structure of this method more obvious.
Ensure that it cannot return a null value.
Mark the return type of this method as @NonNull.
Throw an IllegalArgumentException if the passed archive has an
unexpected type. Note that this condition can never happen with the
current implementation of ArchiveHandle.
Mark the return type of ArchiveHandle.getInputStream() as @NonNull.

This guaranteed non-null return value will simplify the implementation
of the upcoming UnpackJob class.

Bug: 406328303
Flag: EXEMPT no functional change with the current code
Test: atest DocumentsUIGoogleTests:com.android.documentsui.archives
Change-Id: Iefa02e7301b607b0d1396d9f84c5d979670b7d42
parent 25240f01
Loading
Loading
Loading
Loading
+24 −28
Original line number Diff line number Diff line
@@ -114,42 +114,38 @@ abstract class ArchiveEntryInputStream extends InputStream {
        }
    }

    static InputStream create(@NonNull ArchiveHandle archiveHandle,
            @NonNull ArchiveEntry archiveEntry) throws IOException {
        if (archiveHandle == null) {
            throw new IllegalArgumentException("archiveHandle is null");
    static @NonNull InputStream create(@NonNull ArchiveHandle handle, @NonNull ArchiveEntry entry)
            throws IOException {
        if (handle == null) {
            throw new IllegalArgumentException("handle is null");
        }

        if (archiveEntry == null) {
            throw new IllegalArgumentException("ArchiveEntry is empty");
        if (entry == null) {
            throw new IllegalArgumentException("entry is null");
        }

        if (archiveEntry.isDirectory() || archiveEntry.getSize() < 0
                || TextUtils.isEmpty(archiveEntry.getName())) {
        if (entry.isDirectory() || entry.getSize() < 0 || TextUtils.isEmpty(entry.getName())) {
            throw new IllegalArgumentException("ArchiveEntry is an invalid file entry");
        }

        Object commonArchive = archiveHandle.getCommonArchive();

        if (commonArchive instanceof SevenZFile) {
            return new WrapArchiveInputStream(
                (b, off, len) -> ((SevenZFile) commonArchive).read(b, off, len),
                archiveEntry,
                () -> ((SevenZFile) commonArchive).getNextEntry());
        } else if (commonArchive instanceof ZipFile) {
            final InputStream inputStream =
                    ((ZipFile) commonArchive).getInputStream((ZipArchiveEntry) archiveEntry);
            return new WrapZipFileInputStream(
                (b, off, len) -> inputStream.read(b, off, len),
                archiveEntry,
                () -> inputStream.close());
        } else if (commonArchive instanceof ArchiveInputStream) {
            return new WrapArchiveInputStream(
                (b, off, len) -> ((ArchiveInputStream) commonArchive).read(b, off, len),
                archiveEntry,
                () -> ((ArchiveInputStream) commonArchive).getNextEntry());
        }

        return null;
        final Object archive = handle.getCommonArchive();

        if (archive instanceof SevenZFile) {
            final SevenZFile file = (SevenZFile) archive;
            return new WrapArchiveInputStream(file::read, entry, file::getNextEntry);
        }

        if (archive instanceof ZipFile) {
            final ZipFile file = (ZipFile) archive;
            InputStream stream = file.getInputStream((ZipArchiveEntry) entry);
            return new WrapZipFileInputStream(stream::read, entry, stream);
        }

        if (archive instanceof ArchiveInputStream) {
            final ArchiveInputStream stream = (ArchiveInputStream) archive;
            return new WrapArchiveInputStream(stream::read, entry, stream::getNextEntry);
        }

        throw new IllegalArgumentException("Unexpected archive type " + archive);
    }
}
+16 −19
Original line number Diff line number Diff line
@@ -30,6 +30,16 @@ import android.util.Log;

import androidx.annotation.NonNull;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;

import java.io.Closeable;
import java.io.FileInputStream;
import java.io.IOException;
@@ -41,16 +51,6 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;

/**
 * To handle to all of supported support types of archive or compressed+archive files.
 * @param <T> the archive class such as SevenZFile, ZipFile, ArchiveInputStream etc.
@@ -129,17 +129,14 @@ abstract class ArchiveHandle<T> implements Closeable {
    }

    /**
     * Neither SevenZFile nor ArchiveInputStream likes ZipFile that has the API
     * getInputStream(ArchiveEntry), rewind or reset, so it needs to close the
     * current instance and recreate a new one.
     * Gets an InputStream for reading the contents of the given entry.
     *
     * @param archiveEntry the target entry
     * @return the input stream related to archiveEntry
     * @throws IOException invalid file descriptor may raise the IOException
     * @throws CompressorException invalid compress name may raise the CompressException
     * @throws ArchiveException invalid Archive name may raise the ArchiveException
     * @throws IOException         if there is an error when reading the archive file, or if the
     *                             given entry is an encrypted file (in a 7Z or a ZIP archive).
     * @throws CompressorException if there is an error while decompressing the archive data.
     * @throws ArchiveException    if there is an error with archive format itself.
     */
    protected InputStream getInputStream(@NonNull ArchiveEntry archiveEntry)
    protected @NonNull InputStream getInputStream(@NonNull ArchiveEntry archiveEntry)
            throws IOException, CompressorException, ArchiveException {

        if (!isCommonArchiveSupportGetInputStream()) {