public static void salvageCopy(InputStream brokenZip, File salvagedZip,
                                   boolean allowStoredEntries) throws IOException {

        try {
            if (!(brokenZip instanceof RereadableInputStream)) {
                brokenZip = new RereadableInputStream(brokenZip, 50000, true);
            }

            try (ZipArchiveOutputStream outputStream = new ZipArchiveOutputStream(salvagedZip);
                    ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(
                            CloseShieldInputStream.wrap(brokenZip), "UTF8", false,
                            allowStoredEntries)) {
                ZipArchiveEntry zae = zipArchiveInputStream.getNextEntry();
                try {
                    processZAE(zae, zipArchiveInputStream, outputStream);
                } catch (UnsupportedZipFeatureException uzfe) {
                    if (uzfe.getFeature() ==
                            UnsupportedZipFeatureException.Feature.DATA_DESCRIPTOR) {
                        //percolate up to allow for retry
                        throw uzfe;
                    }
                    //else swallow
                } catch (ZipException | EOFException e) {
                    //swallow
                }
                outputStream.flush();
                outputStream.finish();
            } catch (UnsupportedZipFeatureException e) {
                //now retry
                if (allowStoredEntries == false &&
                        e.getFeature() == UnsupportedZipFeatureException.Feature.DATA_DESCRIPTOR) {
                    ((RereadableInputStream) brokenZip).rewind();
                    salvageCopy(brokenZip, salvagedZip, true);
                } else {
                    throw e;
                }
            } catch (IOException e) {
                LOG.warn("problem fixing zip", e);
            }
        } finally {
            brokenZip.close();
        }
    }
This streams the broken zip and rebuilds a new zip that
is at least a valid zip file.  The contents of the final stream
may be truncated, but the result should be a valid zip file.
<p>
This does nothing fancy to fix the underlying broken zip.
<p>
This will close the inputstream

@param brokenZip
@param salvagedZip
@param allowStoredEntries
@throws java.io.IOException
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-zip-commons/src/main/java/org/apache/tika/zip/utils/ZipSalvager.java