ZipFile.Save() fails when there is no root level file

Mar 26, 2008 at 4:33 PM
If I build a directory that contains only subdirectories and no top level files, such as:

C:\zipme\subdir1\
C:\zipme\subdir1\readme.txt
C:\zipme\subdir2\
C:\zipme\subdir2\readme.txt

I get the following exception when calling Save("C:\zipme\") on the ZipFile instance.

System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Ionic.Utils.Zip.ZipEntry.WriteHeader(Stream s, Byte[] bytes) in C:\SourceCode\Branches\MCC MLMv2\Library Projects\Ionic.Utils.Zip\ZipEntry.cs:line 852
at Ionic.Utils.Zip.ZipEntry.Write(Stream s) in C:\SourceCode\Branches\MCC MLMv2\Library Projects\Ionic.Utils.Zip\ZipEntry.cs:line 928
at Ionic.Utils.Zip.ZipFile.Save() in C:\SourceCode\Branches\MCC MLMv2\Library Projects\Ionic.Utils.Zip\ZipFile.cs:line 739

But if I include an actual file at the root level:

C:\zipme\junkfile.txt
C:\zipme\subdir1\
C:\zipme\subdir1\readme.txt
C:\zipme\subdir2\
C:\zipme\subdir2\readme.txt

everything works fine. What am I missing?
Coordinator
Apr 3, 2008 at 5:38 PM
wow! That stinks. Let me check it out.
Coordinator
Apr 3, 2008 at 7:40 PM
Hold on now, when you call zip.Save("c:\zipme\") , you are passing in a directory name, yes?

That is incorrect usage. I guess the Save(string) method should check. But you must specify a filename, not a directory name, when calling that Save() method. Try that ?

Or maybe you are specifying a real filename. I don't know for sure. When I tried this, it worked for me.

If you think you are using it correctly, can you send me a short test case? It should be about 30 lines of code. I just added some unit tests to the DotNetZip solution (not yet released here), and in the test that covers an empty root directory, it just works.

        [TestMethod]
        public void ZipDirectoryWithEmptyRoot()
        {
            int i, j;
            int entries = 0;
 
            string currentDir = System.IO.Directory.GetCurrentDirectory();
 
            string TopLevelDir = GenerateUniqueFilename("tmp");
            System.IO.Directory.CreateDirectory(TopLevelDir);
            _FilesToRemove.Add(TopLevelDir);
 
            int subdirCount = _rnd.Next(2) + 2;
            for (i = 0; i < subdirCount; i++)
            {
                string Subdir = GenerateUniqueFilename("tmp", TopLevelDir);
                System.IO.Directory.CreateDirectory(Subdir);
 
                int fileCount = _rnd.Next(2) + 2;
                for (j = 0; j < fileCount; j++)
                {
                    CreateUniqueFile("bin", Subdir, _rnd.Next(10000) + 5000);
                    entries++; 
                }
            }
 
            string ZipFileToCreate = GenerateUniqueFilename("zip");
            _FilesToRemove.Add(ZipFileToCreate);
 
            Assert.IsFalse(System.IO.File.Exists(ZipFileToCreate), "The temporary zip file '{0}' already exists.", ZipFileToCreate);
 
            System.IO.Directory.SetCurrentDirectory(System.IO.Path.GetDirectoryName(TopLevelDir));
            string RelativeDir = System.IO.Path.GetFileName(TopLevelDir);
 
            using (ZipFile zip = new ZipFile(ZipFileToCreate))
            {
                zip.AddDirectory(RelativeDir);
                zip.Save();
            }
            System.IO.Directory.SetCurrentDirectory(currentDir);
 
 
            Assert.IsTrue(CheckZip(ZipFileToCreate, entries),
                    "Zip file created seems to be invalid.");
 
        }
Coordinator
Apr 19, 2008 at 7:21 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.