SevenZipChecker.java

package edu.jiangxin.apktoolbox.file.password.recovery.checker;

import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.utils.MultiReadOnlySeekableByteChannel;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.channels.SeekableByteChannel;
import java.util.ArrayList;
import java.util.List;

public final class SevenZipChecker extends FileChecker {
    private static final boolean DEBUG = true;

    private boolean isSplitFile = false;

    private File[] splitFiles;

    public SevenZipChecker() {
        super();
    }

    @Override
    public String[] getFileExtensions() {
        return new String[]{"7z", "001"};
    }

    @Override
    public String getFileDescription() {
        return "*.7z";
    }

    @Override
    public String getDescription() {
        return "7Zip Checker";
    }

    @Override
    public boolean prepareChecker() {
        return true;
    }

    @Override
    public void attachFile(File file) {
        super.attachFile(file);
        isSplitFile = isSplitFile();
        splitFiles = getSplitFiles();
    }

    @Override
    public boolean checkPassword(String password) {
        if (DEBUG) {
            logger.info("checkPassword: " + password);
        }
        if (isSplitFile) {
            SevenZFile.Builder builder = new SevenZFile.Builder();
            SeekableByteChannel channel = null;
            SevenZFile sevenZFile = null;
            try {
                channel = MultiReadOnlySeekableByteChannel.forFiles(splitFiles);
                builder.setSeekableByteChannel(channel).setPassword(password.toCharArray());
                sevenZFile = builder.get();
                tryToRead(sevenZFile);
                return true;
            } catch (IOException e) {
                return false;
            } finally {
                IOUtils.closeQuietly(channel);
                IOUtils.closeQuietly(sevenZFile);
            }

        } else {
            SevenZFile sevenZFile = null;
            try {
                SevenZFile.Builder builder = new SevenZFile.Builder().setFile(file).setPassword(password.toCharArray());
                builder.setFile(file).setPassword(password.toCharArray());
                sevenZFile = builder.get();
                tryToRead(sevenZFile);
                return true;
            } catch (IOException e) {
                return false;
            } finally {
                IOUtils.closeQuietly(sevenZFile);
            }
        }
    }

    private void tryToRead(SevenZFile sevenZFile) throws IOException {
        SevenZArchiveEntry entry = sevenZFile.getNextEntry();
        while (entry != null) {
            try (BufferedInputStream bis = new BufferedInputStream(sevenZFile.getInputStream(entry))) {
                byte[] buffer = new byte[1024];
                while (bis.read(buffer) != -1) {
                    // do nothing
                }
            }
            entry = sevenZFile.getNextEntry();
        }
    }

    private boolean isSplitFile() {
        String extension = FilenameUtils.getExtension(file.getName());
        logger.info("isSplitFile extension: {}", extension);
        return "001".equals(extension);
    }

    private File[] getSplitFiles() {
        List<File> fileList = new ArrayList<>();
        String baseName = FilenameUtils.getBaseName(file.getName());
        String parent = file.getParent();
        logger.info("getSplitFiles baseName: {}", baseName);
        for (int i = 1; i < 1000; i++) {
            File file = new File(parent, baseName + "." + String.format("%03d", i));
            if (file.exists()) {
                fileList.add(file);
            } else {
                break;
            }
        }
        logger.info("getSplitFiles: {}", fileList);
        return fileList.toArray(new File[0]);
    }
}