diff --git a/src/main/java/org/jamel/j7zip/ArchiveExtractCallback.java b/src/main/java/org/jamel/j7zip/ArchiveExtractCallback.java index 0199db6..6a772d9 100755 --- a/src/main/java/org/jamel/j7zip/ArchiveExtractCallback.java +++ b/src/main/java/org/jamel/j7zip/ArchiveExtractCallback.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.nio.file.Files; import org.jamel.j7zip.archive.IArchiveExtractCallback; import org.jamel.j7zip.archive.IInArchive; @@ -68,6 +69,7 @@ public OutputStream getStream(SevenZipEntry item) throws IOException { throw new IOException("can't create directory " + file); } } + else Files.createDirectories( file.getParentFile().toPath() ); long pos = item.getPosition(); if (pos == -1 && file.exists()) file.delete(); diff --git a/src/main/java/org/jamel/j7zip/archive/common/CoderMixer2ST.java b/src/main/java/org/jamel/j7zip/archive/common/CoderMixer2ST.java index b63a996..415cab9 100755 --- a/src/main/java/org/jamel/j7zip/archive/common/CoderMixer2ST.java +++ b/src/main/java/org/jamel/j7zip/archive/common/CoderMixer2ST.java @@ -161,7 +161,7 @@ public Result code( } CoderInfo coder = coders.get(i); - if (coder instanceof ICompressSetOutStreamSize) { + if (coder.Coder instanceof ICompressSetOutStreamSize) { ICompressSetOutStreamSize setOutStreamSize = (ICompressSetOutStreamSize) coder.Coder; setOutStreamSize.setOutStreamSize(coder.OutSizePointers.get(0)); } diff --git a/src/main/java/org/jamel/j7zip/archive/sevenZip/Handler.java b/src/main/java/org/jamel/j7zip/archive/sevenZip/Handler.java index 4ab7340..950ea63 100755 --- a/src/main/java/org/jamel/j7zip/archive/sevenZip/Handler.java +++ b/src/main/java/org/jamel/j7zip/archive/sevenZip/Handler.java @@ -1,6 +1,10 @@ package org.jamel.j7zip.archive.sevenZip; import java.io.IOException; +import java.util.Collections; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import org.jamel.j7zip.common.ObjectVector; import org.jamel.j7zip.archive.IArchiveExtractCallback; @@ -12,6 +16,7 @@ public class Handler implements IInArchive { private final ArchiveDatabaseEx database; + private Supplier streamSupplier; private IInStream inStream; @@ -38,6 +43,111 @@ public Result open(IInStream stream, long maxCheckStartPosition) throws IOExcept return Result.OK; } + + public Result open( Supplier stream ) + { + streamSupplier = stream; + try ( var srcStream = streamSupplier.get() ) + { + return open( srcStream, kMaxCheckStartPosition ); + } + catch ( IOException IO ) { IO.printStackTrace(); } + return Result.ERROR_FAIL; + } + + + public Result extract( Supplier extractCallbackSpec ) + { + var exec = Executors.newFixedThreadPool( 4 ); + + for ( ExtractFolderInfo efi : extractFolderInfo() ) + { + if ( efi.UnPackSize > 0 ) exec.execute + ( + () -> extract( efi, extractCallbackSpec.get() ) + ); + } + + try { exec.shutdown(); exec.awaitTermination( 30, TimeUnit.SECONDS ); } + catch ( InterruptedException IE ) { IE.printStackTrace(); } + + return Result.OK; + } + + + private ObjectVector extractFolderInfo() + { + var extractFolderInfoVector = new ObjectVector(); + + for ( int ref2Index = 0; ref2Index < database.files.size(); ref2Index++ ) + { + int folderIndex = database.FileIndexToFolderIndexMap.get( ref2Index ); + + if ( folderIndex == InArchive.kNumNoIndex ) + { + extractFolderInfoVector.add( new ExtractFolderInfo( ref2Index, folderIndex ) ); + continue; + } + + if ( extractFolderInfoVector.isEmpty() || folderIndex != extractFolderInfoVector.last().FolderIndex ) try + { + var efi = new ExtractFolderInfo( InArchive.kNumNoIndex, folderIndex ); + efi.UnPackSize = database.folders.get( folderIndex ).getUnPackSize(); + extractFolderInfoVector.add( efi ); + } + catch ( IOException IO ) { IO.printStackTrace(); } + + var efi = extractFolderInfoVector.last(); + int targetIndex = ref2Index - database.FolderStartFileIndex.get( folderIndex ); + + for ( int index = efi.ExtractStatuses.size(); index <= targetIndex; index++ ) + { + efi.ExtractStatuses.add( index == targetIndex ); + } + } + + // Sort the folders in descending order of size + Collections.sort( extractFolderInfoVector, (a,b) -> -1 * Long.compare( a.UnPackSize, b.UnPackSize ) ); + + return extractFolderInfoVector; + } + + + private void extract( ExtractFolderInfo efi, IArchiveExtractCallback extractCallbackSpec ) + { + try ( var srcStream = streamSupplier.get() ) + { + var folderOutStream = new FolderOutStream(); + var startIndex = database.FolderStartFileIndex.get( efi.FolderIndex ); + folderOutStream.init( this, database, 0, startIndex, efi.ExtractStatuses, extractCallbackSpec ); + + var packStreamIndex = database.FolderStartPackStreamIndex.get( efi.FolderIndex ); + var folderStartPackPos = database.getFolderStreamPos( efi.FolderIndex, 0 ); + var folderInfo = database.folders.get( efi.FolderIndex ); + + var result = new Decoder().decode + ( + srcStream, folderStartPackPos, database.packSizes, + packStreamIndex, folderInfo, folderOutStream + ); + + switch ( result ) + { + case ERROR_NOT_IMPLEMENTED : folderOutStream.flushCorrupted( OperationResult.UNSUPPORTED_METHOD ); break; + case FALSE : folderOutStream.flushCorrupted( OperationResult.DATA_ERROR ); break; + case OK : if ( folderOutStream.wasWritingFinished() != Result.OK ) + { + folderOutStream.flushCorrupted( OperationResult.DATA_ERROR ); + } + } + } + catch ( Exception EX ) + { + EX.printStackTrace(); + } + } + + public Result extract(int[] indices, IArchiveExtractCallback extractCallbackSpec) throws IOException { int numItems = (indices == null ? database.files.size() : indices.length); if (numItems == 0) {