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