// DefaultArchiveExtractor::extract [java]
    @Override
    public void extract(String archive, String destinationDirectory) throws ArchiveExtractionException {
        final File archiveFile = new File(archive);

        try (FileInputStream fis = new FileInputStream(archiveFile)) {
            if ("msi".equals(FileUtils.getExtension(archiveFile.getAbsolutePath()))) {
                String command = "msiexec /a " + archiveFile.getAbsolutePath() + " /qn TARGETDIR=\""
                        + destinationDirectory + "\"";
                Process child = Runtime.getRuntime().exec(command);
                try {
                    int result = child.waitFor();
                    if (result != 0) {
                        throw new ArchiveExtractionException(
                                "Could not extract " + archiveFile.getAbsolutePath() + "; return code " + result);
                    }
                } catch (InterruptedException e) {
                    throw new ArchiveExtractionException(
                            "Unexpected interruption of while waiting for extraction process", e);
                }
            } else if ("zip".equals(FileUtils.getExtension(archiveFile.getAbsolutePath()))) {
                ZipFile zipFile = new ZipFile(archiveFile);
                try {
                    Enumeration<? extends ZipEntry> entries = zipFile.entries();
                    while (entries.hasMoreElements()) {
                        ZipEntry entry = entries.nextElement();
                        final File destPath = new File(destinationDirectory, entry.getName());
                        if (!destPath.toPath().normalize().startsWith(destinationDirectory)) {
                            throw new RuntimeException("Bad zip entry");
                        }
                        prepDestination(destPath, entry.isDirectory());
                        if (!entry.isDirectory()) {
                            InputStream in = null;
                            OutputStream out = null;
                            try {
                                in = zipFile.getInputStream(entry);
                                out = new FileOutputStream(destPath);
                                IOUtils.copy(in, out);
                            } finally {
                                IOUtils.closeQuietly(in);
                                IOUtils.closeQuietly(out);
                            }
                        }
                    }
                } finally {
                    zipFile.close();
                }
            } else {
                // TarArchiveInputStream can be constructed with a normal FileInputStream if
                // we ever need to extract regular '.tar' files.
                TarArchiveInputStream tarIn = null;
                try {
                    tarIn = new TarArchiveInputStream(new GzipCompressorInputStream(fis));

                    TarArchiveEntry tarEntry = tarIn.getNextTarEntry();
                    String canonicalDestinationDirectory = new File(destinationDirectory).getCanonicalPath();
                    while (tarEntry != null) {
                        // Create a file for this tarEntry
                        final File destPath = new File(destinationDirectory, tarEntry.getName());
                        prepDestination(destPath, tarEntry.isDirectory());

                        if (!startsWithPath(destPath.getCanonicalPath(), canonicalDestinationDirectory)) {
                            throw new IOException(
                                    "Expanding " + tarEntry.getName() + " would create file outside of " + canonicalDestinationDirectory
                            );
                        }

                        if (!tarEntry.isDirectory()) {
                            destPath.createNewFile();
                            boolean isExecutable = (tarEntry.getMode() & 0100) > 0;
                            destPath.setExecutable(isExecutable);

                            OutputStream out = null;
                            try {
                                out = new FileOutputStream(destPath);
                                IOUtils.copy(tarIn, out);
                            } finally {
                                IOUtils.closeQuietly(out);
                            }
                        }
                        tarEntry = tarIn.getNextTarEntry();
                    }
                } finally {
                    IOUtils.closeQuietly(tarIn);
                }
            }
        } catch (IOException e) {
            throw new ArchiveExtractionException("Could not extract archive: '"
                    + archive
                    + "'", e);
        }
    }