FastZip.cs 24 KB

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