Merge pull request #1322 from StephenMcConnel/bug23532
[mono.git] / mcs / class / System.IO.Compression.FileSystem / ZipFile.cs
1 //
2 // ZipFile.cs
3 //
4 // Author:
5 //       João Matos <joao.matos@xamarin.com>
6 //       Martin Baulig <martin.baulig@xamarin.com>
7 //
8 // Copyright (c) 2013 Xamarin Inc. (http://www.xamarin.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 using System;
28 using System.Text;
29
30 namespace System.IO.Compression
31 {
32         public static class ZipFile
33         {
34                 public static void CreateFromDirectory (
35                         string sourceDirectoryName, string destinationArchiveFileName)
36                 {
37                         CreateFromDirectory (sourceDirectoryName, destinationArchiveFileName,
38                                 CompressionLevel.Fastest, includeBaseDirectory: false);
39                 }
40
41                 public static void CreateFromDirectory (
42                         string sourceDirectoryName, string destinationArchiveFileName,
43                         CompressionLevel compressionLevel, bool includeBaseDirectory)
44                 {
45                         CreateFromDirectory (sourceDirectoryName, destinationArchiveFileName,
46                                 compressionLevel, includeBaseDirectory, Encoding.UTF8);
47                 }
48
49                 public static void CreateFromDirectory (
50                         string sourceDirectoryName,
51                         string destinationArchiveFileName,
52                         CompressionLevel compressionLevel,
53                         bool includeBaseDirectory,
54                         Encoding entryNameEncoding)
55                 {
56                         if (sourceDirectoryName == null)
57                                 throw new ArgumentNullException ("sourceDirectoryName");
58
59                         if (destinationArchiveFileName == null)
60                                 throw new ArgumentNullException ("destinationArchiveFileName");
61
62                         if (string.IsNullOrWhiteSpace (sourceDirectoryName))
63                                 throw new ArgumentException ("sourceDirectoryName");
64                                 
65                         if (string.IsNullOrWhiteSpace (destinationArchiveFileName))
66                                 throw new ArgumentException ("destinationArchiveFileName");
67
68                         if (entryNameEncoding == Encoding.Unicode ||
69                             entryNameEncoding == Encoding.UTF32 ||
70                             entryNameEncoding == Encoding.UTF7)
71                                 throw new ArgumentException ("entryNameEncoding");
72
73                         if (entryNameEncoding == null)
74                                 entryNameEncoding = Encoding.UTF8;
75
76                         if (!Directory.Exists (sourceDirectoryName))
77                                 throw new DirectoryNotFoundException ("sourceDirectoryName is invalid or does not exist");
78
79                         var sourceDir = new DirectoryInfo (Path.GetFullPath (sourceDirectoryName));
80
81                         string fullBaseName = sourceDir.FullName;
82                         if (includeBaseDirectory && sourceDir.Parent != null)
83                                 fullBaseName = sourceDir.Parent.FullName;
84
85                         bool hasEntries = false;
86                         char[] separators = new char[] {
87                                 Path.DirectorySeparatorChar,
88                                 Path.AltDirectorySeparatorChar
89                         };
90
91                         using (var zipFile = ZipFile.Open (destinationArchiveFileName, ZipArchiveMode.Create,
92                                 entryNameEncoding)) {
93                                 var entries = sourceDir.EnumerateFileSystemInfos ("*", SearchOption.AllDirectories);
94                                 foreach (var entry in entries) {
95                                         hasEntries = true;
96
97                                         int length = entry.FullName.Length - fullBaseName.Length;
98                                         string entryName = entry.FullName.Substring(fullBaseName.Length, length);
99
100                                         entryName = entryName.TrimStart(separators);
101
102                                         if (entry is FileInfo)
103                                                 zipFile.CreateEntryFromFile (entry.FullName, entryName, compressionLevel);
104                                         else
105                                                 zipFile.CreateEntry (entryName + Path.DirectorySeparatorChar);
106                                 }
107
108                                 // Create the base directory even if we had no entries
109                                 if (includeBaseDirectory && !hasEntries)
110                                         zipFile.CreateEntry(sourceDir.Name + Path.DirectorySeparatorChar);
111                         }
112                 }
113
114                 public static void ExtractToDirectory (
115                         string sourceArchiveFileName, string destinationDirectoryName)
116                 {
117                         ExtractToDirectory (sourceArchiveFileName, destinationDirectoryName,
118                                 Encoding.UTF8);
119                 }
120
121                 public static void ExtractToDirectory (
122                         string sourceArchiveFileName, string destinationDirectoryName,
123                         Encoding entryNameEncoding)
124                 {
125                         if (sourceArchiveFileName == null)
126                                 throw new ArgumentNullException ("sourceArchiveFileName");
127
128                         using (ZipArchive zipArchive = ZipFile.Open(sourceArchiveFileName,
129                                 ZipArchiveMode.Read, entryNameEncoding))
130                         {
131                                 zipArchive.ExtractToDirectory(destinationDirectoryName);
132                         }
133                 }
134
135                 public static ZipArchive Open (
136                         string archiveFileName, ZipArchiveMode mode)
137                 {
138                         return Open (archiveFileName, mode);
139                 }
140
141                 public static ZipArchive Open (
142                         string archiveFileName, ZipArchiveMode mode,
143                         Encoding entryNameEncoding)
144                 {
145                         if (archiveFileName == null)
146                                 throw new ArgumentNullException ("archiveFileName");
147
148                         if (string.IsNullOrWhiteSpace (archiveFileName))
149                                 throw new ArgumentException ("archiveFileName");
150
151                         FileStream stream;
152
153                         switch (mode) {
154                         case ZipArchiveMode.Read:
155                                 if (!File.Exists (archiveFileName))
156                                         throw new FileNotFoundException ();
157                                 stream = new FileStream (archiveFileName, FileMode.Open, FileAccess.Read,
158                                         FileShare.Read);
159                                 break;
160                         case ZipArchiveMode.Create:
161                                 if (File.Exists (archiveFileName))
162                                         throw new IOException ("mode is set to Create but the file already exists");
163                                 stream = new FileStream (archiveFileName, FileMode.CreateNew, FileAccess.Write);
164                                 break;
165                         case ZipArchiveMode.Update:
166                                 stream = new FileStream (archiveFileName, FileMode.OpenOrCreate,
167                                         FileAccess.ReadWrite);
168                                 break;
169                         default:
170                                 throw new ArgumentOutOfRangeException ();
171                         }
172
173                         return new ZipArchive (stream, mode, false, entryNameEncoding);
174                 }
175
176                 public static ZipArchive OpenRead (string archiveFileName)
177                 {
178                         return ZipFile.Open (archiveFileName, ZipArchiveMode.Read);
179                 }
180         }
181 }
182