VersionNeededToExtract causes .NET System.IO.Zip to fail read


When opening an existing zip file, in particular one created using .NET System.IO.Zip classes, if that file is saved using DotNetZip, the local entry is written out in its original form, but the central directory entry is updated such that Version Needed To Extract is always set to 20 (unless Zip64 is set). This causes an error with the .NET libraries. The .NET libraries will throw a FileFormatException if there is a mismatch between the local and central entries.
My workaround was simply to use the value of the ZipEntry's VersionNeeded when the central directory is being written. This patch shows the location of the change (v 1.9 of DNZ). It assumes a valid value has already been assigned to the ZipEntry's VersionNeeded, which appears to be the case in my usage scenario (I'm not creating files from scratch).
=== (+4,-2) ZipEntry.Write.cs ===
@@ -80,7 +80,9 @@
         // These are all present in the local file header, but they may be zero values there.
         // So we cannot just copy them.
  • Int16 versionNeededToExtract = (Int16)(_OutputUsesZip64.Value ? 45 : 20);
  • // NOTE: Version Needed To Extract in central directory must be
  • // the same as the local entry or MS .NET System.IO.Zip fails read.
  • Int16 versionNeededToExtract = (Int16)(_OutputUsesZip64.Value ? 45 : VersionNeeded);
         bytes[i++] = (byte)(versionNeededToExtract & 0x00FF);
         bytes[i++] = (byte)((versionNeededToExtract & 0xFF00) >> 8);
Closed Jun 14, 2011 at 3:01 AM by Cheeso
thanks for the bug report and code fix. This is now fixed as of changeset 79080. The first binary with this change will be v1.9.1.6.


toddlucas wrote Oct 23, 2010 at 6:23 AM

It turns out that the VersionNeeded property is zero fro new entries. My fix now has these two lines.
        Int16 versionNeeded = (Int16)(VersionNeeded != 0 ? VersionNeeded : 20);
        Int16 versionNeededToExtract = (Int16)(_OutputUsesZip64.Value ? 45 : versionNeeded);