| 1 | // FastZip.cs
|
|---|
| 2 | //
|
|---|
| 3 | // Copyright 2005 John Reilly
|
|---|
| 4 | //
|
|---|
| 5 | // This program is free software; you can redistribute it and/or
|
|---|
| 6 | // modify it under the terms of the GNU General Public License
|
|---|
| 7 | // as published by the Free Software Foundation; either version 2
|
|---|
| 8 | // of the License, or (at your option) any later version.
|
|---|
| 9 | //
|
|---|
| 10 | // This program is distributed in the hope that it will be useful,
|
|---|
| 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 13 | // GNU General Public License for more details.
|
|---|
| 14 | //
|
|---|
| 15 | // You should have received a copy of the GNU General Public License
|
|---|
| 16 | // along with this program; if not, write to the Free Software
|
|---|
| 17 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|---|
| 18 | //
|
|---|
| 19 | // Linking this library statically or dynamically with other modules is
|
|---|
| 20 | // making a combined work based on this library. Thus, the terms and
|
|---|
| 21 | // conditions of the GNU General Public License cover the whole
|
|---|
| 22 | // combination.
|
|---|
| 23 | //
|
|---|
| 24 | // As a special exception, the copyright holders of this library give you
|
|---|
| 25 | // permission to link this library with independent modules to produce an
|
|---|
| 26 | // executable, regardless of the license terms of these independent
|
|---|
| 27 | // modules, and to copy and distribute the resulting executable under
|
|---|
| 28 | // terms of your choice, provided that you also meet, for each linked
|
|---|
| 29 | // independent module, the terms and conditions of the license of that
|
|---|
| 30 | // module. An independent module is a module which is not derived from
|
|---|
| 31 | // or based on this library. If you modify this library, you may extend
|
|---|
| 32 | // this exception to your version of the library, but you are not
|
|---|
| 33 | // obligated to do so. If you do not wish to do so, delete this
|
|---|
| 34 | // exception statement from your version.
|
|---|
| 35 |
|
|---|
| 36 | using System;
|
|---|
| 37 | using System.IO;
|
|---|
| 38 | using ICSharpCode.SharpZipLib.Core;
|
|---|
| 39 |
|
|---|
| 40 | namespace ICSharpCode.SharpZipLib.Zip
|
|---|
| 41 | {
|
|---|
| 42 | /// <summary>
|
|---|
| 43 | /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.
|
|---|
| 44 | /// </summary>
|
|---|
| 45 | public class FastZipEvents
|
|---|
| 46 | {
|
|---|
| 47 | /// <summary>
|
|---|
| 48 | /// Delegate to invoke when processing directories.
|
|---|
| 49 | /// </summary>
|
|---|
| 50 | public ProcessDirectoryHandler ProcessDirectory;
|
|---|
| 51 |
|
|---|
| 52 | /// <summary>
|
|---|
| 53 | /// Delegate to invoke when processing files.
|
|---|
| 54 | /// </summary>
|
|---|
| 55 | public ProcessFileHandler ProcessFile;
|
|---|
| 56 |
|
|---|
| 57 | /// <summary>
|
|---|
| 58 | /// Delegate to invoke during processing of files.
|
|---|
| 59 | /// </summary>
|
|---|
| 60 | public ProgressHandler Progress;
|
|---|
| 61 |
|
|---|
| 62 | /// <summary>
|
|---|
| 63 | /// Delegate to invoke when processing for a file has been completed.
|
|---|
| 64 | /// </summary>
|
|---|
| 65 | public CompletedFileHandler CompletedFile;
|
|---|
| 66 |
|
|---|
| 67 | /// <summary>
|
|---|
| 68 | /// Delegate to invoke when processing directory failures.
|
|---|
| 69 | /// </summary>
|
|---|
| 70 | public DirectoryFailureHandler DirectoryFailure;
|
|---|
| 71 |
|
|---|
| 72 | /// <summary>
|
|---|
| 73 | /// Delegate to invoke when processing file failures.
|
|---|
| 74 | /// </summary>
|
|---|
| 75 | public FileFailureHandler FileFailure;
|
|---|
| 76 |
|
|---|
| 77 | /// <summary>
|
|---|
| 78 | /// Raise the <see cref="DirectoryFailure">directory failure</see> event.
|
|---|
| 79 | /// </summary>
|
|---|
| 80 | /// <param name="directory">The directory causing the failure.</param>
|
|---|
| 81 | /// <param name="e">The exception for this event.</param>
|
|---|
| 82 | /// <returns>A boolean indicating if execution should continue or not.</returns>
|
|---|
| 83 | public bool OnDirectoryFailure(string directory, Exception e)
|
|---|
| 84 | {
|
|---|
| 85 | bool result = false;
|
|---|
| 86 | DirectoryFailureHandler handler = DirectoryFailure;
|
|---|
| 87 |
|
|---|
| 88 | if ( handler != null ) {
|
|---|
| 89 | ScanFailureEventArgs args = new ScanFailureEventArgs(directory, e);
|
|---|
| 90 | handler(this, args);
|
|---|
| 91 | result = args.ContinueRunning;
|
|---|
| 92 | }
|
|---|
| 93 | return result;
|
|---|
| 94 | }
|
|---|
| 95 |
|
|---|
| 96 | /// <summary>
|
|---|
| 97 | /// Raises the <see cref="FileFailure">file failure delegate</see>.
|
|---|
| 98 | /// </summary>
|
|---|
| 99 | /// <param name="file">The file causing the failure.</param>
|
|---|
| 100 | /// <param name="e">The exception for this failure.</param>
|
|---|
| 101 | /// <returns>A boolean indicating if execution should continue or not.</returns>
|
|---|
| 102 | public bool OnFileFailure(string file, Exception e)
|
|---|
| 103 | {
|
|---|
| 104 | FileFailureHandler handler = FileFailure;
|
|---|
| 105 | bool result = (handler != null);
|
|---|
| 106 |
|
|---|
| 107 | if ( result ) {
|
|---|
| 108 | ScanFailureEventArgs args = new ScanFailureEventArgs(file, e);
|
|---|
| 109 | handler(this, args);
|
|---|
| 110 | result = args.ContinueRunning;
|
|---|
| 111 | }
|
|---|
| 112 | return result;
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | /// <summary>
|
|---|
| 116 | /// Fires the <see cref="ProcessFile">Process File delegate</see>.
|
|---|
| 117 | /// </summary>
|
|---|
| 118 | /// <param name="file">The file being processed.</param>
|
|---|
| 119 | /// <returns>A boolean indicating if execution should continue or not.</returns>
|
|---|
| 120 | public bool OnProcessFile(string file)
|
|---|
| 121 | {
|
|---|
| 122 | bool result = true;
|
|---|
| 123 | ProcessFileHandler handler = ProcessFile;
|
|---|
| 124 |
|
|---|
| 125 | if ( handler != null ) {
|
|---|
| 126 | ScanEventArgs args = new ScanEventArgs(file);
|
|---|
| 127 | ProcessFile(this, args);
|
|---|
| 128 | result = args.ContinueRunning;
|
|---|
| 129 | }
|
|---|
| 130 | return result;
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 | /// <summary>
|
|---|
| 134 | /// Fires the CompletedFile delegate
|
|---|
| 135 | /// </summary>
|
|---|
| 136 | /// <param name="file">The file whose processing has been completed.</param>
|
|---|
| 137 | /// <returns>A boolean indicating if execution should continue or not.</returns>
|
|---|
| 138 | public bool OnCompletedFile(string file)
|
|---|
| 139 | {
|
|---|
| 140 | bool result = true;
|
|---|
| 141 | CompletedFileHandler handler = CompletedFile;
|
|---|
| 142 | if ( handler != null ) {
|
|---|
| 143 | ScanEventArgs args = new ScanEventArgs(file);
|
|---|
| 144 | handler(this, args);
|
|---|
| 145 | result = args.ContinueRunning;
|
|---|
| 146 | }
|
|---|
| 147 | return result;
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|
| 150 | /// <summary>
|
|---|
| 151 | /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.
|
|---|
| 152 | /// </summary>
|
|---|
| 153 | /// <param name="directory">The directory being processed.</param>
|
|---|
| 154 | /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files as determined by the current filter.</param>
|
|---|
| 155 | /// <returns>A <see cref="bool"/> of true if the operation should continue; false otherwise.</returns>
|
|---|
| 156 | public bool OnProcessDirectory(string directory, bool hasMatchingFiles)
|
|---|
| 157 | {
|
|---|
| 158 | bool result = true;
|
|---|
| 159 | ProcessDirectoryHandler handler = ProcessDirectory;
|
|---|
| 160 | if ( handler != null ) {
|
|---|
| 161 | DirectoryEventArgs args = new DirectoryEventArgs(directory, hasMatchingFiles);
|
|---|
| 162 | handler(this, args);
|
|---|
| 163 | result = args.ContinueRunning;
|
|---|
| 164 | }
|
|---|
| 165 | return result;
|
|---|
| 166 | }
|
|---|
| 167 |
|
|---|
| 168 | /// <summary>
|
|---|
| 169 | /// The minimum timespan between <see cref="Progress"/> events.
|
|---|
| 170 | /// </summary>
|
|---|
| 171 | /// <value>The minimum period of time between <see cref="Progress"/> events.</value>
|
|---|
| 172 | /// <seealso cref="Progress"/>
|
|---|
| 173 | public TimeSpan ProgressInterval
|
|---|
| 174 | {
|
|---|
| 175 | get { return progressInterval_; }
|
|---|
| 176 | set { progressInterval_ = value; }
|
|---|
| 177 | }
|
|---|
| 178 |
|
|---|
| 179 | #region Instance Fields
|
|---|
| 180 | TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);
|
|---|
| 181 | #endregion
|
|---|
| 182 | }
|
|---|
| 183 |
|
|---|
| 184 | /// <summary>
|
|---|
| 185 | /// FastZip provides facilities for creating and extracting zip files.
|
|---|
| 186 | /// </summary>
|
|---|
| 187 | public class FastZip
|
|---|
| 188 | {
|
|---|
| 189 | #region Enumerations
|
|---|
| 190 | /// <summary>
|
|---|
| 191 | /// Defines the desired handling when overwriting files during extraction.
|
|---|
| 192 | /// </summary>
|
|---|
| 193 | public enum Overwrite
|
|---|
| 194 | {
|
|---|
| 195 | /// <summary>
|
|---|
| 196 | /// Prompt the user to confirm overwriting
|
|---|
| 197 | /// </summary>
|
|---|
| 198 | Prompt,
|
|---|
| 199 | /// <summary>
|
|---|
| 200 | /// Never overwrite files.
|
|---|
| 201 | /// </summary>
|
|---|
| 202 | Never,
|
|---|
| 203 | /// <summary>
|
|---|
| 204 | /// Always overwrite files.
|
|---|
| 205 | /// </summary>
|
|---|
| 206 | Always
|
|---|
| 207 | }
|
|---|
| 208 | #endregion
|
|---|
| 209 |
|
|---|
| 210 | #region Constructors
|
|---|
| 211 | /// <summary>
|
|---|
| 212 | /// Initialise a default instance of <see cref="FastZip"/>.
|
|---|
| 213 | /// </summary>
|
|---|
| 214 | public FastZip()
|
|---|
| 215 | {
|
|---|
| 216 | }
|
|---|
| 217 |
|
|---|
| 218 | /// <summary>
|
|---|
| 219 | /// Initialise a new instance of <see cref="FastZip"/>
|
|---|
| 220 | /// </summary>
|
|---|
| 221 | /// <param name="events">The <see cref="FastZipEvents">events</see> to use during operations.</param>
|
|---|
| 222 | public FastZip(FastZipEvents events)
|
|---|
| 223 | {
|
|---|
| 224 | events_ = events;
|
|---|
| 225 | }
|
|---|
| 226 | #endregion
|
|---|
| 227 |
|
|---|
| 228 | #region Properties
|
|---|
| 229 | /// <summary>
|
|---|
| 230 | /// Get/set a value indicating wether empty directories should be created.
|
|---|
| 231 | /// </summary>
|
|---|
| 232 | public bool CreateEmptyDirectories
|
|---|
| 233 | {
|
|---|
| 234 | get { return createEmptyDirectories_; }
|
|---|
| 235 | set { createEmptyDirectories_ = value; }
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|
| 238 | #if !NETCF_1_0
|
|---|
| 239 | /// <summary>
|
|---|
| 240 | /// Get / set the password value.
|
|---|
| 241 | /// </summary>
|
|---|
| 242 | public string Password
|
|---|
| 243 | {
|
|---|
| 244 | get { return password_; }
|
|---|
| 245 | set { password_ = value; }
|
|---|
| 246 | }
|
|---|
| 247 | #endif
|
|---|
| 248 |
|
|---|
| 249 | /// <summary>
|
|---|
| 250 | /// Get or set the <see cref="INameTransform"></see> active when creating Zip files.
|
|---|
| 251 | /// </summary>
|
|---|
| 252 | /// <seealso cref="EntryFactory"></seealso>
|
|---|
| 253 | public INameTransform NameTransform
|
|---|
| 254 | {
|
|---|
| 255 | get { return entryFactory_.NameTransform; }
|
|---|
| 256 | set {
|
|---|
| 257 | entryFactory_.NameTransform = value;
|
|---|
| 258 | }
|
|---|
| 259 | }
|
|---|
| 260 |
|
|---|
| 261 | /// <summary>
|
|---|
| 262 | /// Get or set the <see cref="IEntryFactory"></see> active when creating Zip files.
|
|---|
| 263 | /// </summary>
|
|---|
| 264 | public IEntryFactory EntryFactory
|
|---|
| 265 | {
|
|---|
| 266 | get { return entryFactory_; }
|
|---|
| 267 | set {
|
|---|
| 268 | if ( value == null ) {
|
|---|
| 269 | entryFactory_ = new ZipEntryFactory();
|
|---|
| 270 | }
|
|---|
| 271 | else {
|
|---|
| 272 | entryFactory_ = value;
|
|---|
| 273 | }
|
|---|
| 274 | }
|
|---|
| 275 | }
|
|---|
| 276 |
|
|---|
| 277 | /// <summary>
|
|---|
| 278 | /// Gets or sets the setting for <see cref="UseZip64">Zip64 handling when writing.</see>
|
|---|
| 279 | /// </summary>
|
|---|
| 280 | /// <remarks>
|
|---|
| 281 | /// The default value is dynamic which is not backwards compatible with old
|
|---|
| 282 | /// programs and can cause problems with XP's built in compression which cant
|
|---|
| 283 | /// read Zip64 archives. However it does avoid the situation were a large file
|
|---|
| 284 | /// is added and cannot be completed correctly.
|
|---|
| 285 | /// NOTE: Setting the size for entries before they are added is the best solution!
|
|---|
| 286 | /// By default the EntryFactory used by FastZip will set fhe file size.
|
|---|
| 287 | /// </remarks>
|
|---|
| 288 | public UseZip64 UseZip64
|
|---|
| 289 | {
|
|---|
| 290 | get { return useZip64_; }
|
|---|
| 291 | set { useZip64_ = value; }
|
|---|
| 292 | }
|
|---|
| 293 |
|
|---|
| 294 | /// <summary>
|
|---|
| 295 | /// Get/set a value indicating wether file dates and times should
|
|---|
| 296 | /// be restored when extracting files from an archive.
|
|---|
| 297 | /// </summary>
|
|---|
| 298 | /// <remarks>The default value is false.</remarks>
|
|---|
| 299 | public bool RestoreDateTimeOnExtract
|
|---|
| 300 | {
|
|---|
| 301 | get {
|
|---|
| 302 | return restoreDateTimeOnExtract_;
|
|---|
| 303 | }
|
|---|
| 304 | set {
|
|---|
| 305 | restoreDateTimeOnExtract_ = value;
|
|---|
| 306 | }
|
|---|
| 307 | }
|
|---|
| 308 |
|
|---|
| 309 | /// <summary>
|
|---|
| 310 | /// Get/set a value indicating wether file attributes should
|
|---|
| 311 | /// be restored during extract operations
|
|---|
| 312 | /// </summary>
|
|---|
| 313 | public bool RestoreAttributesOnExtract
|
|---|
| 314 | {
|
|---|
| 315 | get { return restoreAttributesOnExtract_; }
|
|---|
| 316 | set { restoreAttributesOnExtract_ = value; }
|
|---|
| 317 | }
|
|---|
| 318 | #endregion
|
|---|
| 319 |
|
|---|
| 320 | #region Delegates
|
|---|
| 321 | /// <summary>
|
|---|
| 322 | /// Delegate called when confirming overwriting of files.
|
|---|
| 323 | /// </summary>
|
|---|
| 324 | public delegate bool ConfirmOverwriteDelegate(string fileName);
|
|---|
| 325 | #endregion
|
|---|
| 326 |
|
|---|
| 327 | #region CreateZip
|
|---|
| 328 | /// <summary>
|
|---|
| 329 | /// Create a zip file.
|
|---|
| 330 | /// </summary>
|
|---|
| 331 | /// <param name="zipFileName">The name of the zip file to create.</param>
|
|---|
| 332 | /// <param name="sourceDirectory">The directory to source files from.</param>
|
|---|
| 333 | /// <param name="recurse">True to recurse directories, false for no recursion.</param>
|
|---|
| 334 | /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
|
|---|
| 335 | /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
|
|---|
| 336 | public void CreateZip(string zipFileName, string sourceDirectory,
|
|---|
| 337 | bool recurse, string fileFilter, string directoryFilter)
|
|---|
| 338 | {
|
|---|
| 339 | CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, directoryFilter);
|
|---|
| 340 | }
|
|---|
| 341 |
|
|---|
| 342 | /// <summary>
|
|---|
| 343 | /// Create a zip file/archive.
|
|---|
| 344 | /// </summary>
|
|---|
| 345 | /// <param name="zipFileName">The name of the zip file to create.</param>
|
|---|
| 346 | /// <param name="sourceDirectory">The directory to obtain files and directories from.</param>
|
|---|
| 347 | /// <param name="recurse">True to recurse directories, false for no recursion.</param>
|
|---|
| 348 | /// <param name="fileFilter">The file filter to apply.</param>
|
|---|
| 349 | public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)
|
|---|
| 350 | {
|
|---|
| 351 | CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, null);
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 | /// <summary>
|
|---|
| 355 | /// Create a zip archive sending output to the <paramref name="outputStream"/> passed.
|
|---|
| 356 | /// </summary>
|
|---|
| 357 | /// <param name="outputStream">The stream to write archive data to.</param>
|
|---|
| 358 | /// <param name="sourceDirectory">The directory to source files from.</param>
|
|---|
| 359 | /// <param name="recurse">True to recurse directories, false for no recursion.</param>
|
|---|
| 360 | /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
|
|---|
| 361 | /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
|
|---|
| 362 | public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse, string fileFilter, string directoryFilter)
|
|---|
| 363 | {
|
|---|
| 364 | NameTransform = new ZipNameTransform(sourceDirectory);
|
|---|
| 365 | sourceDirectory_ = sourceDirectory;
|
|---|
| 366 |
|
|---|
| 367 | using ( outputStream_ = new ZipOutputStream(outputStream) ) {
|
|---|
| 368 |
|
|---|
| 369 | #if !NETCF_1_0
|
|---|
| 370 | if ( password_ != null ) {
|
|---|
| 371 | outputStream_.Password = password_;
|
|---|
| 372 | }
|
|---|
| 373 | #endif
|
|---|
| 374 |
|
|---|
| 375 | outputStream_.UseZip64 = UseZip64;
|
|---|
| 376 | FileSystemScanner scanner = new FileSystemScanner(fileFilter, directoryFilter);
|
|---|
| 377 | scanner.ProcessFile += new ProcessFileHandler(ProcessFile);
|
|---|
| 378 | if ( this.CreateEmptyDirectories ) {
|
|---|
| 379 | scanner.ProcessDirectory += new ProcessDirectoryHandler(ProcessDirectory);
|
|---|
| 380 | }
|
|---|
| 381 |
|
|---|
| 382 | if (events_ != null) {
|
|---|
| 383 | if ( events_.FileFailure != null ) {
|
|---|
| 384 | scanner.FileFailure += events_.FileFailure;
|
|---|
| 385 | }
|
|---|
| 386 |
|
|---|
| 387 | if ( events_.DirectoryFailure != null ) {
|
|---|
| 388 | scanner.DirectoryFailure += events_.DirectoryFailure;
|
|---|
| 389 | }
|
|---|
| 390 | }
|
|---|
| 391 |
|
|---|
| 392 | scanner.Scan(sourceDirectory, recurse);
|
|---|
| 393 | }
|
|---|
| 394 | }
|
|---|
| 395 |
|
|---|
| 396 | #endregion
|
|---|
| 397 |
|
|---|
| 398 | #region ExtractZip
|
|---|
| 399 | /// <summary>
|
|---|
| 400 | /// Extract the contents of a zip file.
|
|---|
| 401 | /// </summary>
|
|---|
| 402 | /// <param name="zipFileName">The zip file to extract from.</param>
|
|---|
| 403 | /// <param name="targetDirectory">The directory to save extracted information in.</param>
|
|---|
| 404 | /// <param name="fileFilter">A filter to apply to files.</param>
|
|---|
| 405 | public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)
|
|---|
| 406 | {
|
|---|
| 407 | ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null, restoreDateTimeOnExtract_);
|
|---|
| 408 | }
|
|---|
| 409 |
|
|---|
| 410 | /// <summary>
|
|---|
| 411 | /// Extract the contents of a zip file.
|
|---|
| 412 | /// </summary>
|
|---|
| 413 | /// <param name="zipFileName">The zip file to extract from.</param>
|
|---|
| 414 | /// <param name="targetDirectory">The directory to save extracted information in.</param>
|
|---|
| 415 | /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
|
|---|
| 416 | /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
|
|---|
| 417 | /// <param name="fileFilter">A filter to apply to files.</param>
|
|---|
| 418 | /// <param name="directoryFilter">A filter to apply to directories.</param>
|
|---|
| 419 | /// <param name="restoreDateTime">Flag indicating wether to restore the date and time for extracted files.</param>
|
|---|
| 420 | public void ExtractZip(string zipFileName, string targetDirectory,
|
|---|
| 421 | Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
|
|---|
| 422 | string fileFilter, string directoryFilter, bool restoreDateTime)
|
|---|
| 423 | {
|
|---|
| 424 | if ( (overwrite == Overwrite.Prompt) && (confirmDelegate == null) ) {
|
|---|
| 425 | throw new ArgumentNullException("confirmDelegate");
|
|---|
| 426 | }
|
|---|
| 427 |
|
|---|
| 428 | continueRunning_ = true;
|
|---|
| 429 | overwrite_ = overwrite;
|
|---|
| 430 | confirmDelegate_ = confirmDelegate;
|
|---|
| 431 | extractNameTransform_ = new WindowsNameTransform(targetDirectory);
|
|---|
| 432 |
|
|---|
| 433 | fileFilter_ = new NameFilter(fileFilter);
|
|---|
| 434 | directoryFilter_ = new NameFilter(directoryFilter);
|
|---|
| 435 | restoreDateTimeOnExtract_ = restoreDateTime;
|
|---|
| 436 |
|
|---|
| 437 | using ( zipFile_ = new ZipFile(zipFileName) ) {
|
|---|
| 438 |
|
|---|
| 439 | #if !NETCF_1_0
|
|---|
| 440 | if (password_ != null) {
|
|---|
| 441 | zipFile_.Password = password_;
|
|---|
| 442 | }
|
|---|
| 443 | #endif
|
|---|
| 444 |
|
|---|
| 445 | System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator();
|
|---|
| 446 | while ( continueRunning_ && enumerator.MoveNext()) {
|
|---|
| 447 | ZipEntry entry = (ZipEntry) enumerator.Current;
|
|---|
| 448 | if ( entry.IsFile )
|
|---|
| 449 | {
|
|---|
| 450 | // TODO Path.GetDirectory can fail here on invalid characters.
|
|---|
| 451 | if ( directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name) ) {
|
|---|
| 452 | ExtractEntry(entry);
|
|---|
| 453 | }
|
|---|
| 454 | }
|
|---|
| 455 | else if ( entry.IsDirectory ) {
|
|---|
| 456 | if ( directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories ) {
|
|---|
| 457 | ExtractEntry(entry);
|
|---|
| 458 | }
|
|---|
| 459 | }
|
|---|
| 460 | else {
|
|---|
| 461 | // Do nothing for volume labels etc...
|
|---|
| 462 | }
|
|---|
| 463 | }
|
|---|
| 464 | }
|
|---|
| 465 | }
|
|---|
| 466 | #endregion
|
|---|
| 467 |
|
|---|
| 468 | #region Internal Processing
|
|---|
| 469 | void ProcessDirectory(object sender, DirectoryEventArgs e)
|
|---|
| 470 | {
|
|---|
| 471 | if ( !e.HasMatchingFiles && CreateEmptyDirectories ) {
|
|---|
| 472 | if ( events_ != null ) {
|
|---|
| 473 | events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);
|
|---|
| 474 | }
|
|---|
| 475 |
|
|---|
| 476 | if ( e.ContinueRunning ) {
|
|---|
| 477 | if (e.Name != sourceDirectory_) {
|
|---|
| 478 | ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name);
|
|---|
| 479 | outputStream_.PutNextEntry(entry);
|
|---|
| 480 | }
|
|---|
| 481 | }
|
|---|
| 482 | }
|
|---|
| 483 | }
|
|---|
| 484 |
|
|---|
| 485 | void ProcessFile(object sender, ScanEventArgs e)
|
|---|
| 486 | {
|
|---|
| 487 | if ( (events_ != null) && (events_.ProcessFile != null) ) {
|
|---|
| 488 | events_.ProcessFile(sender, e);
|
|---|
| 489 | }
|
|---|
| 490 |
|
|---|
| 491 | if ( e.ContinueRunning ) {
|
|---|
| 492 | using( FileStream stream=File.OpenRead(e.Name) ) {
|
|---|
| 493 | ZipEntry entry=entryFactory_.MakeFileEntry(e.Name);
|
|---|
| 494 | outputStream_.PutNextEntry(entry);
|
|---|
| 495 | AddFileContents(e.Name, stream);
|
|---|
| 496 | }
|
|---|
| 497 | }
|
|---|
| 498 | }
|
|---|
| 499 |
|
|---|
| 500 | void AddFileContents(string name, Stream stream)
|
|---|
| 501 | {
|
|---|
| 502 | if( stream==null ) {
|
|---|
| 503 | throw new ArgumentNullException("stream");
|
|---|
| 504 | }
|
|---|
| 505 |
|
|---|
| 506 | if( buffer_==null ) {
|
|---|
| 507 | buffer_=new byte[4096];
|
|---|
| 508 | }
|
|---|
| 509 |
|
|---|
| 510 | if( (events_!=null)&&(events_.Progress!=null) ) {
|
|---|
| 511 | StreamUtils.Copy(stream, outputStream_, buffer_,
|
|---|
| 512 | events_.Progress, events_.ProgressInterval, this, name);
|
|---|
| 513 | }
|
|---|
| 514 | else {
|
|---|
| 515 | StreamUtils.Copy(stream, outputStream_, buffer_);
|
|---|
| 516 | }
|
|---|
| 517 |
|
|---|
| 518 | if( events_!=null ) {
|
|---|
| 519 | continueRunning_=events_.OnCompletedFile(name);
|
|---|
| 520 | }
|
|---|
| 521 | }
|
|---|
| 522 |
|
|---|
| 523 | void ExtractFileEntry(ZipEntry entry, string targetName)
|
|---|
| 524 | {
|
|---|
| 525 | bool proceed = true;
|
|---|
| 526 | if ( overwrite_ != Overwrite.Always ) {
|
|---|
| 527 | if ( File.Exists(targetName) ) {
|
|---|
| 528 | if ( (overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null) ) {
|
|---|
| 529 | proceed = confirmDelegate_(targetName);
|
|---|
| 530 | }
|
|---|
| 531 | else {
|
|---|
| 532 | proceed = false;
|
|---|
| 533 | }
|
|---|
| 534 | }
|
|---|
| 535 | }
|
|---|
| 536 |
|
|---|
| 537 | if ( proceed ) {
|
|---|
| 538 | if ( events_ != null ) {
|
|---|
| 539 | continueRunning_ = events_.OnProcessFile(entry.Name);
|
|---|
| 540 | }
|
|---|
| 541 |
|
|---|
| 542 | if ( continueRunning_ ) {
|
|---|
| 543 | try {
|
|---|
| 544 | using ( FileStream outputStream = File.Create(targetName) ) {
|
|---|
| 545 | if ( buffer_ == null ) {
|
|---|
| 546 | buffer_ = new byte[4096];
|
|---|
| 547 | }
|
|---|
| 548 | if ((events_ != null) && (events_.Progress != null))
|
|---|
| 549 | {
|
|---|
| 550 | StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_,
|
|---|
| 551 | events_.Progress, events_.ProgressInterval, this, entry.Name, entry.Size);
|
|---|
| 552 | }
|
|---|
| 553 | else
|
|---|
| 554 | {
|
|---|
| 555 | StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);
|
|---|
| 556 | }
|
|---|
| 557 |
|
|---|
| 558 | if (events_ != null) {
|
|---|
| 559 | continueRunning_ = events_.OnCompletedFile(entry.Name);
|
|---|
| 560 | }
|
|---|
| 561 | }
|
|---|
| 562 |
|
|---|
| 563 | #if !NETCF_1_0 && !NETCF_2_0
|
|---|
| 564 | if ( restoreDateTimeOnExtract_ ) {
|
|---|
| 565 | File.SetLastWriteTime(targetName, entry.DateTime);
|
|---|
| 566 | }
|
|---|
| 567 |
|
|---|
| 568 | if ( RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1)) {
|
|---|
| 569 | FileAttributes fileAttributes = (FileAttributes) entry.ExternalFileAttributes;
|
|---|
| 570 | // TODO: FastZip - Setting of other file attributes on extraction is a little trickier.
|
|---|
| 571 | fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttributes.Hidden);
|
|---|
| 572 | File.SetAttributes(targetName, fileAttributes);
|
|---|
| 573 | }
|
|---|
| 574 | #endif
|
|---|
| 575 | }
|
|---|
| 576 | catch(Exception ex) {
|
|---|
| 577 | if ( events_ != null ) {
|
|---|
| 578 | continueRunning_ = events_.OnFileFailure(targetName, ex);
|
|---|
| 579 | }
|
|---|
| 580 | else {
|
|---|
| 581 | continueRunning_ = false;
|
|---|
| 582 | throw;
|
|---|
| 583 | }
|
|---|
| 584 | }
|
|---|
| 585 | }
|
|---|
| 586 | }
|
|---|
| 587 | }
|
|---|
| 588 |
|
|---|
| 589 | void ExtractEntry(ZipEntry entry)
|
|---|
| 590 | {
|
|---|
| 591 | bool doExtraction = entry.IsCompressionMethodSupported();
|
|---|
| 592 | string targetName = entry.Name;
|
|---|
| 593 |
|
|---|
| 594 | if ( doExtraction ) {
|
|---|
| 595 | if ( entry.IsFile ) {
|
|---|
| 596 | targetName = extractNameTransform_.TransformFile(targetName);
|
|---|
| 597 | }
|
|---|
| 598 | else if ( entry.IsDirectory ) {
|
|---|
| 599 | targetName = extractNameTransform_.TransformDirectory(targetName);
|
|---|
| 600 | }
|
|---|
| 601 |
|
|---|
| 602 | doExtraction = !((targetName == null) || (targetName.Length == 0));
|
|---|
| 603 | }
|
|---|
| 604 |
|
|---|
| 605 | // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?
|
|---|
| 606 |
|
|---|
| 607 | string dirName = null;
|
|---|
| 608 |
|
|---|
| 609 | if ( doExtraction ) {
|
|---|
| 610 | if ( entry.IsDirectory ) {
|
|---|
| 611 | dirName = targetName;
|
|---|
| 612 | }
|
|---|
| 613 | else {
|
|---|
| 614 | dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
|
|---|
| 615 | }
|
|---|
| 616 | }
|
|---|
| 617 |
|
|---|
| 618 | if ( doExtraction && !Directory.Exists(dirName) ) {
|
|---|
| 619 | if ( !entry.IsDirectory || CreateEmptyDirectories ) {
|
|---|
| 620 | try {
|
|---|
| 621 | Directory.CreateDirectory(dirName);
|
|---|
| 622 | }
|
|---|
| 623 | catch (Exception ex) {
|
|---|
| 624 | doExtraction = false;
|
|---|
| 625 | if ( events_ != null ) {
|
|---|
| 626 | if ( entry.IsDirectory ) {
|
|---|
| 627 | continueRunning_ = events_.OnDirectoryFailure(targetName, ex);
|
|---|
| 628 | }
|
|---|
| 629 | else {
|
|---|
| 630 | continueRunning_ = events_.OnFileFailure(targetName, ex);
|
|---|
| 631 | }
|
|---|
| 632 | }
|
|---|
| 633 | else {
|
|---|
| 634 | continueRunning_ = false;
|
|---|
| 635 | throw;
|
|---|
| 636 | }
|
|---|
| 637 | }
|
|---|
| 638 | }
|
|---|
| 639 | }
|
|---|
| 640 |
|
|---|
| 641 | if ( doExtraction && entry.IsFile ) {
|
|---|
| 642 | ExtractFileEntry(entry, targetName);
|
|---|
| 643 | }
|
|---|
| 644 | }
|
|---|
| 645 |
|
|---|
| 646 | static int MakeExternalAttributes(FileInfo info)
|
|---|
| 647 | {
|
|---|
| 648 | return (int)info.Attributes;
|
|---|
| 649 | }
|
|---|
| 650 |
|
|---|
| 651 | #if NET_1_0 || NET_1_1 || NETCF_1_0
|
|---|
| 652 | static bool NameIsValid(string name)
|
|---|
| 653 | {
|
|---|
| 654 | return (name != null) &&
|
|---|
| 655 | (name.Length > 0) &&
|
|---|
| 656 | (name.IndexOfAny(Path.InvalidPathChars) < 0);
|
|---|
| 657 | }
|
|---|
| 658 | #else
|
|---|
| 659 | static bool NameIsValid(string name)
|
|---|
| 660 | {
|
|---|
| 661 | return (name != null) &&
|
|---|
| 662 | (name.Length > 0) &&
|
|---|
| 663 | (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);
|
|---|
| 664 | }
|
|---|
| 665 | #endif
|
|---|
| 666 | #endregion
|
|---|
| 667 |
|
|---|
| 668 | #region Instance Fields
|
|---|
| 669 | bool continueRunning_;
|
|---|
| 670 | byte[] buffer_;
|
|---|
| 671 | ZipOutputStream outputStream_;
|
|---|
| 672 | ZipFile zipFile_;
|
|---|
| 673 | string sourceDirectory_;
|
|---|
| 674 | NameFilter fileFilter_;
|
|---|
| 675 | NameFilter directoryFilter_;
|
|---|
| 676 | Overwrite overwrite_;
|
|---|
| 677 | ConfirmOverwriteDelegate confirmDelegate_;
|
|---|
| 678 |
|
|---|
| 679 | bool restoreDateTimeOnExtract_;
|
|---|
| 680 | bool restoreAttributesOnExtract_;
|
|---|
| 681 | bool createEmptyDirectories_;
|
|---|
| 682 | FastZipEvents events_;
|
|---|
| 683 | IEntryFactory entryFactory_ = new ZipEntryFactory();
|
|---|
| 684 | INameTransform extractNameTransform_;
|
|---|
| 685 | UseZip64 useZip64_=UseZip64.Dynamic;
|
|---|
| 686 |
|
|---|
| 687 | #if !NETCF_1_0
|
|---|
| 688 | string password_;
|
|---|
| 689 | #endif
|
|---|
| 690 |
|
|---|
| 691 | #endregion
|
|---|
| 692 | }
|
|---|
| 693 | }
|
|---|