ComponentOne Zip for WinRT XAML (C1Zip) can extract and compress files into ZIP archives with support for encryption (passwords). This is significant because the standard ZipArchive class does not support encryption. If you are trying to open an existing archive that is encrypted, you can extract the files by setting the C1ZipFile.Password property after opening the stream to the file. For example, the code below opens an encrypted zip named “Pictures” from embedded resources in a project named “ZipEncryptionSample.”


using C1.C1Zip;  

C1ZipFile _zip = new C1ZipFile();  

// get stream to file  
// this could be a file picker or StorageFile approach instead.  
Assembly asm = typeof(MainPage).GetTypeInfo().Assembly;  
Stream stream = asm.GetManifestResourceStream("ZipEncryptionSample.Pictures.zip");  

// open file with C1Zip  
_zip.Open(stream);  

// set password to decrypt file after it’s been opened  
_zip.Password = "componentone";  

// OPTIONAL: display file contents in a FlexGrid control  
c1FlexGrid1.ItemsSource = _zip.Entries;  

Once opened, the C1ZipFile.Entries collection contains the collection of files. The Open method works similarly to the Create method. Both methods associate the C1ZipFile class to a file stream on the user’s machine, except one is for writing and one is for reading. Typically with C1ZipFile you should perform either an Open or Create operation first before setting the password or adding entries to the zip. You will notice that C1ZipFile does not need to know the password to simply open and obtain a list of contained files within the zip archive. The password comes into play when you further try to open and read a particular file within the archive. You can do so using the C1ZipEntry.OpenReader method.


using (var stream = _zip.Entries[0].OpenReader())  
{  
    var sr = new System.IO.StreamReader(stream);  
    _tbContent.Text = sr.ReadToEnd();  
}  

Zip Builder Sample

Not only can C1Zip be used to open and decrypt a zip archive, but it can be used to compress and create encrypted archives. Let’s build a Windows Store sample application that allows the user to build a zip archive using C1Zip. It will feature a file picker dialog that allows the user to select any number of files. We will display the files in a C1FlexGrid control and allow the user to remove files before compressing. When the user is ready to compress the files, we will allow them to encrypt the archive with a password. Let’s start by creating a blank Windows Store C# application. Then drag a C1FlexGrid control from your toolbox onto MainPage.xaml. This will add the necessary reference to the ComponentOne Studio for WinRT XAML (note: you should install this first to see the controls in your toolbox). Add three buttons to the top of the page for adding files, removing files and compressing the files. Also let’s add a CheckBox and TextBox duo to handle the optional password encryption. You could put these into a pop-up dialog, but this is the simplest example for our purposes. Below is the content for MainPage.xaml.


<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">  
    <Grid.RowDefinitions>  
        <RowDefinition Height="Auto"/>  
        <RowDefinition />  
    </Grid.RowDefinitions>  
    <StackPanel Orientation="Horizontal">  
        <Button x:Name="btnAddFile" Content="Add Files" Click="btnAddFile_Click" />  
        <Button x:Name="btnRemove" Content="Remove Selected" Click="btnRemove_Click" />  
        <Button x:Name="btnCompressEncrypt" Content="Compress to..." Click="btnCompressEncrypt_Click"/>  
        <CheckBox x:Name="chkEncrypt" Content="Encrypt with password" Margin="5"/>  
        <TextBox x:Name="txtPassword" IsEnabled="{Binding ElementName=chkEncrypt, Path=IsChecked}" Width="200" Margin="5"/>  
    </StackPanel>  
    <FlexGrid:C1FlexGrid x:Name="c1FlexGrid1" SelectionMode="Row" Grid.Row="1"/>  
</Grid>  

In our code behind we need to initialize a C1ZipFile as well as a List that will store the files the user wishes to zip.


private C1ZipFile _zip;  
private List<StorageFile> _files;  

public MainPage()  
{  
    this.InitializeComponent();  

    // create a zip file to work with  
    _zip = new C1ZipFile();  

    // create list to store files prior to zipping  
    _files = new List<StorageFile>();  
}  

Next let’s handle when the user clicks the Add Files button. This purely launches a FileOpenPicker and puts the selected files into our list. It does nothing with C1Zip yet.


// launches file picker to select files to be zipped  
private async void btnAddFile_Click(object sender, RoutedEventArgs e)  
{  
    try  
    {  
        var picker = new Windows.Storage.Pickers.FileOpenPicker();  
        picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.List;  
        picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;  
        picker.FileTypeFilter.Add("*");  

        var files = await picker.PickMultipleFilesAsync();  
        if (files != null)  
        {  
            foreach (var f in files)  
            {  
                _files.Add(f);  
            }  
        }  
    }  
    catch  
    {  
        // snapped?  
    }  
    RefreshView();  
}  

It’s important to note why we are not just adding the files directly to C1ZipFile.Entries collection. This is because we have not yet called Open or Create on the C1ZipFile. You should always add entries and set the password after you have associated the C1ZipFile with a stream to the user’s machine. So instead we simply store the files to this List rather than directly to the _zip.Entries. The following code will remove a selected file from the C1FlexGrid control. We also define a RefreshView method which updates the C1FlexGrid. These are just a nice little additions, but again they have nothing to do with C1Zip.


// removes selected file(s) from the list  
private void btnRemove_Click(object sender, RoutedEventArgs e)  
{  
    foreach (StorageFile file in c1FlexGrid1.SelectedItems)  
    {  
        _files.Remove(file);  
    }  
    RefreshView();  
}  

// refresh view when collection is modified  
void RefreshView()  
{  
    var sel = c1FlexGrid1.SelectedItem;  
    c1FlexGrid1.ItemsSource = null;  
    c1FlexGrid1.ItemsSource = _files;  
    c1FlexGrid1.SelectedItem = sel;  
}  

Now we are ready to handle the Compress Files button click event. This will launch a FileSavePicker which will let the user name and locate where they want to save the compressed zip archive. We now get access to a file stream so we can call the C1ZipFile.Create method. After we call Create, we can set the password and add entries.


// compresses all files into selected zip file with option for encryption  
private async void btnCompressEncrypt_Click(object sender, RoutedEventArgs e)  
{  
    try  
    {  
        FileSavePicker savePicker = new FileSavePicker();  
        savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;  
        savePicker.FileTypeChoices.Add("Zip Archive", new List<string>() { ".zip" });  
        savePicker.DefaultFileExtension = ".zip";  

        StorageFile file = await savePicker.PickSaveFileAsync();  
        if (file != null)  
        {  
            // create zip from file picker stream  
            _zip.Create(await file.OpenStreamForWriteAsync());  

            // set password  
            if ((bool)chkEncrypt.IsChecked)  
            {  
                _zip.Password = txtPassword.Text;  
            }  

            // add files to zip  
            foreach (StorageFile f in _files)  
            {  
                await _zip.Entries.AddAsync(f);  
            }  

            // close zip file  
            _zip.CloseBatch();  
        }  
    }  
    catch  
    {  
        // snapped?  
    }  
}  

Finally, it’s important to call the CloseBatch method to complete the zip archive. Otherwise the file stream will remain open (you could add more files later if you’d like).

Conclusion

Download the complete sample here: ZipEncryptionSample.zip. Also, check out Russ’s blog post here which shows a complete sample for opening and reading a zip archive.