!include once #1034352 // zip4j srecord noeq Zip4j_CopySubSetOfZipFile(File zipIn, File zipOut, IPred fileFilter) { ZipModel zipModel; HeaderWriter headerWriter; new net.lingala.zip4j.progress.ProgressMonitor progressMonitor; int bufferSize = InternalZipConstants.BUFF_SIZE; Charset charset; run { try (var randomAccessFile = new RandomAccessFile(zipIn, RandomAccessFileMode.READ.getValue())) { zipModel = new HeaderReader().readAllHeaders(randomAccessFile, buildConfig()); zipModel.setZipFile(zipIn); } temp outputStream = new SplitOutputStream(zipOut); temp inputStream = new RandomAccessFile(zipModel.getZipFile(), RandomAccessFileMode.READ.getValue()); long currentFileCopyPointer = 0; L sortedFileHeaders = sortedByComparator(zipModel.getCentralDirectory().getFileHeaders(), (o1, o2) -> { if (eq(o1.getFileName(), o2.getFileName())) ret 0; ret cmp(o1.getOffsetLocalHeader(), o2.getOffsetLocalHeader()); }); for (fileHeader : sortedFileHeaders) { long lengthOfCurrentEntry = getOffsetOfNextEntry(sortedFileHeaders, fileHeader, zipModel) - outputStream.getFilePointer(); if (!fileFilter.get(fileHeader.getFileName())) { updateHeaders(sortedFileHeaders, fileHeader, lengthOfCurrentEntry); if (!zipModel.getCentralDirectory().getFileHeaders().remove(fileHeader)) { throw new ZipException("Could not remove entry from list of central directory headers"); } currentFileCopyPointer += lengthOfCurrentEntry; } else { // copy complete entry without any changes currentFileCopyPointer += super.copyFile(inputStream, outputStream, currentFileCopyPointer, lengthOfCurrentEntry, progressMonitor, taskParameters.zip4jConfig.getBufferSize()); } } headerWriter.finalizeZipFile(zipModel, outputStream, taskParameters.zip4jConfig.getCharset()); } long getOffsetOfNextEntry(L sortedFileHeaders, FileHeader fileHeader, ZipModel zipModel) throws ZipException { int indexOfFileHeader = getIndexOfFileHeader(sortedFileHeaders, fileHeader); if (indexOfFileHeader == sortedFileHeaders.size() - 1) ret HeaderUtil.getOffsetStartOfCentralDirectory(zipModel); else ret sortedFileHeaders.get(indexOfFileHeader + 1).getOffsetLocalHeader(); } long copyFile(RandomAccessFile randomAccessFile, OutputStream outputStream, long start, long length, ProgressMonitor progressMonitor, int bufferSize) throws IOException { net.lingala.zip4j.util.FileUtils.copyFile(randomAccessFile, outputStream, start, start + length, progressMonitor, bufferSize); ret length; } private void updateHeaders(List sortedFileHeaders, FileHeader fileHeaderThatWasRemoved, long offsetToSubtract) throws ZipException { updateOffsetsForAllSubsequentFileHeaders(sortedFileHeaders, zipModel, fileHeaderThatWasRemoved, negate(offsetToSubtract)); EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = zipModel.getEndOfCentralDirectoryRecord(); endOfCentralDirectoryRecord.setOffsetOfStartOfCentralDirectory( endOfCentralDirectoryRecord.getOffsetOfStartOfCentralDirectory() - offsetToSubtract); endOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectory( endOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectory() - 1); if (endOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectoryOnThisDisk() > 0) { endOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectoryOnThisDisk( endOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectoryOnThisDisk() - 1); } if (zipModel.isZip64Format()) { zipModel.getZip64EndOfCentralDirectoryRecord().setOffsetStartCentralDirectoryWRTStartDiskNumber( zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber() - offsetToSubtract); zipModel.getZip64EndOfCentralDirectoryRecord().setTotalNumberOfEntriesInCentralDirectoryOnThisDisk( zipModel.getZip64EndOfCentralDirectoryRecord().getTotalNumberOfEntriesInCentralDirectory() - 1); zipModel.getZip64EndOfCentralDirectoryLocator().setOffsetZip64EndOfCentralDirectoryRecord( zipModel.getZip64EndOfCentralDirectoryLocator().getOffsetZip64EndOfCentralDirectoryRecord() - offsetToSubtract); } } private long negate(long val) { if (val == Long.MIN_VALUE) { throw new ArithmeticException("long overflow"); } return -val; } Zip4jConfig buildConfig() { return new Zip4jConfig(charset, bufferSize); } }