If Zip64Option.AsNecessary (or Zip64Option.Always but not Zip64Option.Never) is used when streaming a zip file (to a non-seekable stream), the generated zip can not be unzipped with Mac OSX Archive Utility. A .cpgz file is created instead as Archive Utility thinks the zip is a corrupted or uncompressed file so it tries to recompress it. However the same zip file can be opened/unzipped on Windows so it's actually not corrupted. There is no problem with a zip file if it's written to a seekable stream even if Zip64 is turned on. I guess it should be about the "bit 3, streamed output" which is active when a non-seekable stream is used. I see this was discussed before here:
http://dotnetzip.codeplex.com/discussions/59740
I have tested on Mac OSX 10.5.5 (purposely on relatively an old version), here are my findings:
- If I use Safari (v3.1.2), there is no problem with the streamed zip file. Safari automatically extracts the streamed zip to the Downloads folder when the download is completed. Safari seems to have a built-in zip module which doesn’t cause any problems.
- If I use Firefox (v3.6.13), the streamed zip is saved and there is no automatic extraction. When I try to open the downloaded zip with “Archive Utility”, it doesn’t extract and instead creates a .cpgz file.
-
The problem is obviously with Archive Utility which cannot understand this kind of zip files. I have not tested with recent versions of Mac OSX so maybe newer versions of Archive Utility on these systems will not cause the problem. However I need to be compatible with all platforms so I need to find a way to make these generated zip files work out of the box without requiring the user to install an advanced/updated unzip utility.
I know that you suggested MemoryStream or FileStream workarounds to some people before but they are not much suitable for web applications where memory and disk space is important. Also with those methods, the user will have to wait for the zip generation to be completed before starting the download. However I need to stream the zip on the fly so that the user immediately sees the browser's "Open/Save As" dialog. Also I need to do it without turning off Zip64 feature so that I can allow zip files larger than 4GB.
I have found that there was a similar problem with the other zip library SharpZibLib and suggested fix was setting entry size before writing to the stream as discussed here:
http://igorbrejc.net/development/c/sharpziplib-making-it-work-for-linuxmac
I tried to apply the similar fix to DotNetZip. I first made read-only property ZipEntry.UncompressedSize settable and tried to set it to the actual file size in my code like this:
ZipFile zipFile = new ZipFile();
zipFile.UseZip64WhenSaving = Zip64Option.AsNecessary;
zipFile.AlternateEncoding = Encoding.UTF8;
zipFile.AlternateEncodingUsage = ZipOption.AsNecessary;
ZipEntry zipEntry = zipFile.AddFile(itemPath, basePath);
zipEntry.UncompressedSize = fileInfo.Length;
zipFile.Save(zipFileStream);
However this didn't have an effect. Later I fiddled with ZipEntry.Write.cs and tried to change some entry header values like CompressedSize, UnCompressedSize and Crc with no results. I think it must be about these 3 values set in header or in descriptor following the file data. When I use Zip64Option.Never, the file is ok. In my tests, I am zipping small files, I mean no big files to even require Zip64. However whether I use Zip64Option.AsNecessary or Zip64Option.Always, the generated zip causes the same problem.
Can you figure out what maybe be confusing utilities like Archive Utility in this specific case?