Search code examples
c#.netvb.net7zipsevenzipsharp

How to extract a multi volume 7z file using SevenZipSharp?


I generated a multi volume 7z file using SevenZipSharp library.

The problem I have is that when I try to extract the file, I get a exception about an invalid casting:

Unable to cast object

of type 'SevenZip.InMultiStreamWrapper' to type 'SevenZip.InStreamWrapper'.

The method that throws the exception is SevenZipExtractor.Check().

This is a sample code written in Vb.Net to reproduce the extraction problem, but I also can accept a C# solution:

Public Overridable Function Extract(ByVal sourceFilePath As String,
                                    ByVal outputDirectorypath As String,
                                    ByVal password As String) As String

    If String.IsNullOrEmpty(password) Then
        Me.extractor = New SevenZipExtractor(sourceFilePath)
    Else
        Me.extractor = New SevenZipExtractor(sourceFilePath, password)
    End If

    ' Check for password matches doing an integrity check.
    If Me.extractor.Check() Then
        ' Start the extraction.
        Me.extractor.ExtractArchive(outputDirectorypath)

    Else
        Throw New Exception(
              "Failed to extract, maybe the provided password does not match?.")

    End If

    Return outputDirectorypath

End Function

If I ignore the integrity check, with a multi volume file that has a password set, then I cannot extract it because another exception occurs...

Probablly is a bug in their source-code, but I ask to be sure, because it's very strange that the library does not support extracting multi volume files...


Solution

  • Probablly is a bug in their source-code

    This is indeed the case.

    Looking at the SevenZipExtractor.cs source code, we see the following line (inside the method finally block, so it always executes):

    ((InStreamWrapper)_archiveStream).Dispose();
    

    where the _archiveStream is a class field of type IInStream (note the I) which is an interface type that does not derive from IDisposable, hence has no Dispose method.

    Going deeper, we can see that it is initialized with instance of either InStreamWrapper or InMultiStreamWrapper class. While they both share common base class StreamWrapper, the later does not inherit from the former, hence the cast exception.

    Fixing it is quite easy if you are willing to modify the source code. Just replace the above line with:

    if (_archiveStream is IDisposable)
        ((IDisposable)_archiveStream).Dispose();
    

    However

    If I ignore the integrity check, with a multi volume file that has a password set, then I cannot extract it because another exception occurs...

    They do not call the Check method internally, and there should not be any relation of whether you call Check or not before calling ExtractArchive. So I doubt that fixing the above bug will prevent the another exception you are talking about.