Xceed .NET Libraries Documentation
Reading and writing nested Zip archives
Welcome to Xceed .NET, .NET Standard and Xamarin Libraries! > Task-Based Help > Zip and streaming capabilities > Zipping > Reading and writing nested Zip archives

The following examples show how to use the ZipReader.GetItemDataStream and ZipWriter.GetItemDataStream methods to allow the component to easily handle nested zip archives.

A nested zip archive is when an item in an archive is another zip archive. By providing the stream returned by the method to a new instance of ZipWriter or ZipReader, a nested zip file will be created or read.

The first example shows how the ZipWriter.GetItemDataStream() method can be used to create a nested Zip archive.

private void NestedArchiveExample( Stream someStream )
{
  using( ZipWriter writer = new ZipWriter( someStream ) )
  {
    ZipItemLocalHeader header = new ZipItemLocalHeader();

    header.FileName = "File1.zip";
    writer.WriteItemLocalHeader( header );

    // Create a write stream that wraps the item's data
    using( Stream itemStream = writer.GetItemDataStream() )
    {
      // Feed the item stream to a new instance of ZipWriter
      using( ZipWriter nestedWriter = new ZipWriter( itemStream ) )
      {
        /* The 'using' statement will insure the nested zip file is properly terminated */

        // Add an item and some data into the nested zip file
        header.FileName = "File1.dat";
        nestedWriter.WriteItemLocalHeader( header );
        nestedWriter.WriteItemData( MediumFile1 );
      }
    }
  }
}
Private Sub NestedArchiveExample(ByVal someStream As Stream)
  Using writer As New ZipWriter(someStream)
    Dim header As New ZipItemLocalHeader()

    header.FileName = "File1.zip"
    writer.WriteItemLocalHeader(header)

    ' Create a write stream that wraps the item's data
    Using itemStream As Stream = writer.GetItemDataStream()
      ' Feed the item stream to a new instance of ZipWriter
      Using nestedWriter As New ZipWriter(itemStream)
        ' The 'using' statement will insure the nested zip file is properly terminated

        ' Add an item and some data into the nested zip file
        header.FileName = "File1.dat"
        nestedWriter.WriteItemLocalHeader(header)
        nestedWriter.WriteItemData(MediumFile1)
      End Using
    End Using
  End Using
End Sub

The second example shows how the ZipReader.GetItemDataStream method can be used to read a nested Zip archive.

private void ReadZipArchive( Stream archiveStream )
{
  using( ZipReader reader = new ZipReader( archiveStream ) )
  {
    ZipItemLocalHeader header;

    while( ( header = reader.ReadItemLocalHeader() ) != null )
    {
      /* The component will not automatically identity what is and is
      * not a nested zip file. The application needs to have its own mechanism.
      *
      * This example will keep it simple and just look at the item's file name extension. */

      // If the item's extension is .zip
      if( StringComparer.OrdinalIgnoreCase.Compare( Path.GetExtension( header.FileName ), ".zip" ) == 0 )
      {
        // Create a read stream that wraps the item's data
        using( Stream itemStream = reader.GetItemDataStream() )
        {
          /* NOTE: While using a recursive call here makes for elegant and compact code that
          * helps illustrate the concept of nested zip archives, a maliciously crafted zip file
          * made up of a large number of nested zip files could make this code cause a stack overflow
          * due to excessive recursion. */

          // Call ourselves to read the nested archive
          this.ReadZipArchive( itemStream );
        }

        /* IMPORTANT: Before we can move on to the next item in the archive, ZipReader must have
        * reached the end of the current item's data. Reading a nested zip file does not ensure
        * this, so we need to make sure here by reading any remaining data into a dummy stream.
        *
        * Failure to do this will result in a ZipReaderException that reports that the object
        * is not in the correct state to read the next item header. */

        // Make sure we reach the end of the item's data
        reader.ReadItemData( Stream.Null );
      }
      else
      {
        // This example does not concern itself with normal items
        reader.ReadItemData( Stream.Null );
      }
    }
  }
}
Private Sub ReadZipArchive(ByVal archiveStream As Stream)
  Using reader As New ZipReader(archiveStream)
    Dim header As ZipItemLocalHeader

    header = reader.ReadItemLocalHeader()
    Do While header IsNot Nothing
'      The component will not automatically identity what is and is
'      not a nested zip file. The application needs to have its own mechanism.
'     
'      This example will keep it simple and just look at the item's file name extension.

      ' If the item's extension is .zip
      If StringComparer.OrdinalIgnoreCase.Compare(Path.GetExtension(header.FileName), ".zip") = 0 Then
        ' Create a read stream that wraps the item's data
        Using itemStream As Stream = reader.GetItemDataStream()
'          NOTE: While using a recursive call here makes for elegant and compact code that
'          helps illustrate the concept of nested zip archives, a maliciously crafted zip file
'          made up of a large number of nested zip files could make this code cause a stack overflow
'          due to excessive recursion.

          ' Call ourselves to read the nested archive
          Me.ReadZipArchive(itemStream)
        End Using

'        IMPORTANT: Before we can move on to the next item in the archive, ZipReader must have
'        reached the end of the current item's data. Reading a nested zip file does not ensure
'        this, so we need to make sure here by reading any remaining data into a dummy stream.
'       
'        Failure to do this will result in a ZipReaderException that reports that the object
'        is not in the correct state to read the next item header.

        ' Make sure we reach the end of the item's data
        reader.ReadItemData(Stream.Null)
      Else
        ' This example does not concern itself with normal items
        reader.ReadItemData(Stream.Null)
      End If
      header = reader.ReadItemLocalHeader()
    Loop
  End Using
End Sub