3 // Copyright 2005 John Reilly
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software
\r
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
19 // Linking this library statically or dynamically with other modules is
\r
20 // making a combined work based on this library. Thus, the terms and
\r
21 // conditions of the GNU General Public License cover the whole
\r
24 // As a special exception, the copyright holders of this library give you
\r
25 // permission to link this library with independent modules to produce an
\r
26 // executable, regardless of the license terms of these independent
\r
27 // modules, and to copy and distribute the resulting executable under
\r
28 // terms of your choice, provided that you also meet, for each linked
\r
29 // independent module, the terms and conditions of the license of that
\r
30 // module. An independent module is a module which is not derived from
\r
31 // or based on this library. If you modify this library, you may extend
\r
32 // this exception to your version of the library, but you are not
\r
33 // obligated to do so. If you do not wish to do so, delete this
\r
34 // exception statement from your version.
\r
39 using ICSharpCode.SharpZipLib.Core;
\r
41 namespace ICSharpCode.SharpZipLib.Zip
\r
44 /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.
\r
46 public class FastZipEvents
\r
49 /// Delegate to invoke when processing directories.
\r
51 public ProcessDirectoryDelegate ProcessDirectory;
\r
54 /// Delegate to invoke when processing files.
\r
56 public ProcessFileDelegate ProcessFile;
\r
59 /// Delegate to invoke when processing directory failures.
\r
61 public DirectoryFailureDelegate DirectoryFailure;
\r
64 /// Delegate to invoke when processing file failures.
\r
66 public FileFailureDelegate FileFailure;
\r
69 /// Raise the directory failure event.
\r
71 /// <param name="directory">The directory.</param>
\r
72 /// <param name="e">The exception for this event.</param>
\r
73 public void OnDirectoryFailure(string directory, Exception e)
\r
75 if ( DirectoryFailure != null ) {
\r
76 ScanFailureEventArgs args = new ScanFailureEventArgs(directory, e);
\r
77 DirectoryFailure(this, args);
\r
82 /// Raises the file failure event.
\r
84 /// <param name="file">The file for this event.</param>
\r
85 /// <param name="e">The exception for this event.</param>
\r
86 public void OnFileFailure(string file, Exception e)
\r
88 if ( FileFailure != null ) {
\r
89 ScanFailureEventArgs args = new ScanFailureEventArgs(file, e);
\r
90 FileFailure(this, args);
\r
95 /// Raises the ProcessFileEvent.
\r
97 /// <param name="file">The file for this event.</param>
\r
98 public void OnProcessFile(string file)
\r
100 if ( ProcessFile != null ) {
\r
101 ScanEventArgs args = new ScanEventArgs(file);
\r
102 ProcessFile(this, args);
\r
107 /// Raises the ProcessDirectoryEvent.
\r
109 /// <param name="directory">The directory for this event.</param>
\r
110 /// <param name="hasMatchingFiles">Flag indicating if directory has matching files as determined by the current filter.</param>
\r
111 public void OnProcessDirectory(string directory, bool hasMatchingFiles)
\r
113 if ( ProcessDirectory != null ) {
\r
114 DirectoryEventArgs args = new DirectoryEventArgs(directory, hasMatchingFiles);
\r
115 ProcessDirectory(this, args);
\r
122 /// FastZip provides facilities for creating and extracting zip files.
\r
123 /// Only relative paths are supported.
\r
125 public class FastZip
\r
128 /// Initialize a default instance of FastZip.
\r
132 this.events = null;
\r
136 /// Initialise a new instance of <see cref="FastZip"/>
\r
138 /// <param name="events"></param>
\r
139 public FastZip(FastZipEvents events)
\r
141 this.events = events;
\r
145 /// Defines the desired handling when overwriting files.
\r
147 public enum Overwrite {
\r
149 /// Prompt the user to confirm overwriting
\r
153 /// Never overwrite files.
\r
157 /// Always overwrite files.
\r
163 /// Get/set a value indicating wether empty directories should be created.
\r
165 public bool CreateEmptyDirectories
\r
167 get { return createEmptyDirectories; }
\r
168 set { createEmptyDirectories = value; }
\r
172 /// Delegate called when confirming overwriting of files.
\r
174 public delegate bool ConfirmOverwriteDelegate(string fileName);
\r
177 /// Create a zip file.
\r
179 /// <param name="zipFileName">The name of the zip file to create.</param>
\r
180 /// <param name="sourceDirectory">The directory to source files from.</param>
\r
181 /// <param name="recurse">True to recurse directories, false for no recursion.</param>
\r
182 /// <param name="fileFilter">The file filter to apply.</param>
\r
183 /// <param name="directoryFilter">The directory filter to apply.</param>
\r
184 public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter, string directoryFilter)
\r
186 NameTransform = new ZipNameTransform(true, sourceDirectory);
\r
187 this.sourceDirectory = sourceDirectory;
\r
189 outputStream = new ZipOutputStream(File.Create(zipFileName));
\r
191 FileSystemScanner scanner = new FileSystemScanner(fileFilter, directoryFilter);
\r
192 scanner.ProcessFile += new ProcessFileDelegate(ProcessFile);
\r
193 if ( this.CreateEmptyDirectories ) {
\r
194 scanner.ProcessDirectory += new ProcessDirectoryDelegate(ProcessDirectory);
\r
196 scanner.Scan(sourceDirectory, recurse);
\r
199 outputStream.Close();
\r
204 /// Create a zip file/archive.
\r
206 /// <param name="zipFileName">The name of the zip file to create.</param>
\r
207 /// <param name="sourceDirectory">The directory to obtain files and directories from.</param>
\r
208 /// <param name="recurse">True to recurse directories, false for no recursion.</param>
\r
209 /// <param name="fileFilter">The file filter to apply.</param>
\r
210 public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)
\r
212 CreateZip(zipFileName, sourceDirectory, recurse, fileFilter, null);
\r
216 /// Extract the contents of a zip file.
\r
218 /// <param name="zipFileName">The zip file to extract from.</param>
\r
219 /// <param name="targetDirectory">The directory to save extracted information in.</param>
\r
220 /// <param name="fileFilter">A filter to apply to files.</param>
\r
221 public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)
\r
223 ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null);
\r
227 /// Exatract the contents of a zip file.
\r
229 /// <param name="zipFileName">The zip file to extract from.</param>
\r
230 /// <param name="targetDirectory">The directory to save extracted information in.</param>
\r
231 /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
\r
232 /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
\r
233 /// <param name="fileFilter">A filter to apply to files.</param>
\r
234 /// <param name="directoryFilter">A filter to apply to directories.</param>
\r
235 public void ExtractZip(string zipFileName, string targetDirectory,
\r
236 Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
\r
237 string fileFilter, string directoryFilter)
\r
239 if ((overwrite == Overwrite.Prompt) && (confirmDelegate == null)) {
\r
240 throw new ArgumentNullException("confirmDelegate");
\r
242 this.overwrite = overwrite;
\r
243 this.confirmDelegate = confirmDelegate;
\r
244 this.targetDirectory = targetDirectory;
\r
245 this.fileFilter = new NameFilter(fileFilter);
\r
246 this.directoryFilter = new NameFilter(directoryFilter);
\r
248 inputStream = new ZipInputStream(File.OpenRead(zipFileName));
\r
252 if (password != null) {
\r
253 inputStream.Password = password;
\r
257 while ( (entry = inputStream.GetNextEntry()) != null ) {
\r
258 if ( this.directoryFilter.IsMatch(Path.GetDirectoryName(entry.Name)) && this.fileFilter.IsMatch(entry.Name) ) {
\r
259 ExtractEntry(entry);
\r
264 inputStream.Close();
\r
268 void ProcessDirectory(object sender, DirectoryEventArgs e)
\r
270 if ( !e.HasMatchingFiles && createEmptyDirectories ) {
\r
271 if ( events != null ) {
\r
272 events.OnProcessDirectory(e.Name, e.HasMatchingFiles);
\r
275 if (e.Name != sourceDirectory) {
\r
276 string cleanedName = nameTransform.TransformDirectory(e.Name);
\r
277 ZipEntry entry = new ZipEntry(cleanedName);
\r
278 outputStream.PutNextEntry(entry);
\r
283 void ProcessFile(object sender, ScanEventArgs e)
\r
285 if ( events != null ) {
\r
286 events.OnProcessFile(e.Name);
\r
288 string cleanedName = nameTransform.TransformFile(e.Name);
\r
289 ZipEntry entry = new ZipEntry(cleanedName);
\r
290 outputStream.PutNextEntry(entry);
\r
291 AddFileContents(e.Name);
\r
294 void AddFileContents(string name)
\r
296 if ( buffer == null ) {
\r
297 buffer = new byte[4096];
\r
300 FileStream stream = File.OpenRead(name);
\r
304 length = stream.Read(buffer, 0, buffer.Length);
\r
305 outputStream.Write(buffer, 0, length);
\r
306 } while ( length > 0 );
\r
313 void ExtractFileEntry(ZipEntry entry, string targetName)
\r
315 bool proceed = true;
\r
316 if ((overwrite == Overwrite.Prompt) && (confirmDelegate != null)) {
\r
317 if (File.Exists(targetName) == true) {
\r
318 proceed = confirmDelegate(targetName);
\r
324 if ( events != null ) {
\r
325 events.OnProcessFile(entry.Name);
\r
328 FileStream streamWriter = File.Create(targetName);
\r
331 if ( buffer == null ) {
\r
332 buffer = new byte[4096];
\r
338 size = inputStream.Read(buffer, 0, buffer.Length);
\r
339 streamWriter.Write(buffer, 0, size);
\r
340 } while (size > 0);
\r
343 streamWriter.Close();
\r
346 if (restoreDateTime) {
\r
347 File.SetLastWriteTime(targetName, entry.DateTime);
\r
352 bool NameIsValid(string name)
\r
354 return name != null && name.Length > 0 && name.IndexOfAny(Path.InvalidPathChars) < 0;
\r
357 void ExtractEntry(ZipEntry entry)
\r
359 bool doExtraction = NameIsValid(entry.Name);
\r
361 string dirName = null;
\r
362 string targetName = null;
\r
364 if ( doExtraction ) {
\r
365 string entryFileName;
\r
366 if (Path.IsPathRooted(entry.Name)) {
\r
367 string workName = Path.GetPathRoot(entry.Name);
\r
368 workName = entry.Name.Substring(workName.Length);
\r
369 entryFileName = Path.Combine(Path.GetDirectoryName(workName), Path.GetFileName(entry.Name));
\r
371 entryFileName = entry.Name;
\r
374 targetName = Path.Combine(targetDirectory, entryFileName);
\r
375 dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
\r
377 doExtraction = doExtraction && (entryFileName.Length > 0);
\r
380 if ( doExtraction && !Directory.Exists(dirName) )
\r
382 if ( !entry.IsDirectory || this.CreateEmptyDirectories ) {
\r
384 Directory.CreateDirectory(dirName);
\r
387 doExtraction = false;
\r
392 if ( doExtraction && entry.IsFile ) {
\r
393 ExtractFileEntry(entry, targetName);
\r
398 /// Get or set the <see cref="ZipNameTransform"> active when creating Zip files.</see>
\r
400 public ZipNameTransform NameTransform
\r
402 get { return nameTransform; }
\r
404 if ( value == null ) {
\r
405 nameTransform = new ZipNameTransform();
\r
408 nameTransform = value;
\r
413 #region Instance Fields
\r
415 ZipOutputStream outputStream;
\r
416 ZipInputStream inputStream;
\r
417 string password = null;
\r
418 string targetDirectory;
\r
419 string sourceDirectory;
\r
420 NameFilter fileFilter;
\r
421 NameFilter directoryFilter;
\r
422 Overwrite overwrite;
\r
423 ConfirmOverwriteDelegate confirmDelegate;
\r
424 bool restoreDateTime = false;
\r
425 bool createEmptyDirectories = false;
\r
426 FastZipEvents events;
\r
427 ZipNameTransform nameTransform;
\r