Archive

Posts Tagged ‘DotNetZip’

HowTo: Use DotNetZip (Ionic.Zip) library in Silverlight

If you want to use the latest DotNetZip library (version 1.9.1.8) with Silverlight, you should get a patched version from http://dotnetzip.codeplex.com/workitem/14049, instead of the official download for Silverlight.

It seems the Silverlight build in 1.9.1.8 official download doesn’t work correctly, since it tries to get IBM437 Encoding (as the original ZIP spec required) from Silverlight, but that encoding is not available via Encoding.GetEncoding method in Silverlight (neither encoder and decoder fallbacks for GetEncoding are available as in .NET 4.5).

So the patched version uses Unicode encoding instead (only UTF-8 and Unicode [UTF-16] Encodings are available in Silverlight), although it could have also used a text encoding class generator for the missing encoding and change the source code similar to how Mike Taulty had done with an older version of DotNetZip.

I do prefer the Unicode approach, since using the IBM437 codepage would have issues with Unicode filenames. ZIPs with such filenames are supported fine by most modern ZIP viewers, including Windows Explorer’s Compressed Folders views in recent versions of Windows.

HowTo: Write directly into a ZIP stream using DotNetZip

At ClipFlair’s Playground Silverlight app I’m using DotNetZip library (Ionic.Zip namespace) for writing saved component state to a .ZIP file. In fact the Activity container there can create one .ZIP for each state that contains one .ZIP per-component it hosts (it can even host multiple instances of its own Activity component type to have nested Activities in its ZUI interface).

DotNetZip is a perfect match for Silverlight’s security restrictions, where OpenFileDialog and SaveFileDialog only give you a stream to work with (unless your app has been granted elevated trust), since apart from working with filesystem files and folders it allows you to also give it content to compress in the form of a stream.

Note: the latest DotNetZip 1.9.1.8 official version for Silverlight doesn’t work correctly – you need a patched build, see: https://zoomicon.wordpress.com/2012/11/25/howto-use-dotnetzip-ionic-zip-library-in-silverlight/

For working with streams at DotNetZip there are two options (as explained at http://dotnetzip.codeplex.com/discussions/231712):

1) pass it an in-memory buffer (this is a non-optimal method)

public override void SaveOptions(ZipFile zip, string zipFolder = "")  
{
base.SaveOptions(zip, zipFolder);
MemoryStream
stream = new MemoryStream(); //non-optimal, uses memory buffer
gridCaptions.WriteCaptions(stream, "captions.srt"); stream.Position = 0;
zip.AddEntry(zipFolder + "/captions.srt", stream);
}

2) the other is to pass it a write delegate for a method that writes the data to a stream that DotNetZip will pass to it when needed.

public override void SaveOptions(ZipFile zip, string zipFolder = "")
{
  base.SaveOptions(zip, zipFolder);
  zip.AddEntry(zipFolder + "/captions.srt", SaveCaptions);
}

public void SaveCaptions(string entryName, Stream stream)
{
  gridCaptions.WriteCaptions(stream, entryName);
}

 

In case one needs to pass more parameters (apart from the zip entry name and the stream that DotNetZip passes to the delegate), they could instantiate a class instance and keep the parameter there, then pass a method of that class via the delegate to DotNetZip. An easier way is to use an anonymous method and define it in a context where the parameter is available, e.g. as a local variable.

public override void SaveOptions(ZipFile zip, string zipFolder = "")
{
  base.SaveOptions(zip, zipFolder);
  foreach (BaseWindow window in activity.Windows)
    SaveWindow(zip, zipFolder, window);
}

private static void SaveWindow(ZipFile zip, string zipFolder, BaseWindow window)
{
  string title = ((string)window.Title).TrimStart(); 
//using TrimStart() to not have filenames start with
//space chars in case it's an issue with ZIP spec
if (title == "") title = window.GetType().Name; zip.AddEntry( zipFolder + "/" + title + " - " + Guid.NewGuid() + ".clipflair.zip", new WriteDelegate((entryName, stream) => { window.SaveOptions(stream); }) );
//save ZIP file for child window }
%d bloggers like this: