Tuesday, December 2, 2008

Windows XP Unzip Errors With SharpZipLib

Great Utility

SharpZipLib is a great little library that helps you programmatically compress/decompress zip archives. If your needs aren't too exotic (ie. you need to programmatically zip/unzip a series of files/folders) this could very well be your ticket.

You've probably heard of it before (it's been around for quite a while), some sample usage might look like this (compresses a file).

using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipFilePath)))
{
//Compression level 0-9 (9 is highest)
zipStream.SetLevel(GetCompressionLevel());

//Add an entry to our zip file
ZipEntry entry = new ZipEntry(Path.GetFileName(sourceFilePath));
entry.DateTime = DateTime.Now;
zipStream.PutNextEntry(entry);

byte[] buffer = new byte[4096];
int byteCount = 0;

using (FileStream inputStream = File.OpenRead(sourceFilePath))
{
byteCount = inputStream.Read(buffer, 0, buffer.Length);
while (byteCount > 0)
{
zipStream.Write(buffer, 0, byteCount);
byteCount = inputStream.Read(buffer, 0, buffer.Length);
}
}
}

This is pretty normal usage. It adds a zip entry to an archive and creates said archive. What might confuse you though is the error you'll get if you try to to unpack the archive using a legacy unzip tool (ie. the stock Windows XP decompression tool).

The stock Windows XP extraction tool won't be able to unpack the archive and will complain about the archive being "invalid or corrupted" if you try to extract the archive contents.

The Compressed (zipped) Folder is invalid or corrupted.

Zip64 Extensions

What's happening here is that the utility is enabling Zip64 extensions for the archive, and some older utilities can't read Zip64 Extensions. You could simply turn off Zip64 Extensions, but this will cause problems when you start adding files larger than 4GB to your archive.

A better solution is to make a mild tweak to the way we add files to the archive. By specifying the size of the file we're adding, the ZipOutputStream can decide whether or not to use the Zip64 extensions. If we don't need them then they'll be turned off automatically. The mild tweak below fixes the error from the above code:

...
ZipEntry entry = new ZipEntry(Path.GetFileName(sourceFilePath));
entry.DateTime = DateTime.Now;
/* By specifying a size, SharpZipLib will turn on/off UseZip64 based on the file sizes. If Zip64 is ON
* some legacy zip utilities (ie. Windows XP) who can't read Zip64 will be unable to unpack the archive.
* If Zip64 is OFF, zip archives will be unable to support files larger than 4GB. */
entry.Size = new FileInfo(sourceFilePath).Length;
zipStream.PutNextEntry(entry);
...

Hope that helps someone. That error drove me crazy for a while and I didn't find much via Google.

Best,
Tyler