PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/Tools/ZipIt/ZipIt.cs

#
C# | 495 lines | 431 code | 40 blank | 24 comment | 29 complexity | 01d08241198ad4577ccc8f3abaabe2c6 MD5 | raw file
Possible License(s): Apache-2.0, CC-BY-SA-3.0
  1. // ZipIt.cs
  2. //
  3. // ----------------------------------------------------------------------
  4. // Copyright (c) 2006-2011 Dino Chiesa. All rights reserved.
  5. //
  6. // This example is released under the Microsoft Permissive License of
  7. // October 2006. See the license.txt file accompanying this release for
  8. // full details.
  9. //
  10. // ----------------------------------------------------------------------
  11. //
  12. // This utility zips up a set of files and directories specified on the command line.
  13. //
  14. // compile with:
  15. // csc /debug+ /target:exe /r:Ionic.Zip.dll /out:ZipIt.exe ZipIt.cs
  16. //
  17. // Fri, 23 Feb 2007 11:51
  18. //
  19. using System;
  20. using System.IO;
  21. using Ionic.Zip;
  22. namespace Ionic.Zip.Examples
  23. {
  24. public class ZipIt
  25. {
  26. private static void Usage()
  27. {
  28. string UsageMessage =
  29. "Zipit.exe: zip up a directory, file, or a set of them, into a zipfile.\n" +
  30. " Depends on Ionic's DotNetZip library. This is version {0} of the utility.\n" +
  31. "usage:\n ZipIt.exe <ZipFileToCreate> [arguments]\n" +
  32. "\narguments: \n" +
  33. " <directory> | <file> - a directory or file to add to the archive.\n" +
  34. " -64 - use ZIP64 extensions, for large files or large numbers of files.\n" +
  35. " -aes - use WinZip-compatible AES 256-bit encryption for entries\n" +
  36. " subsequently added to the archive. Requires a password.\n" +
  37. " -cp <codepage> - use the specified numeric codepage to encode entry filenames \n" +
  38. " and comments, instead of the default IBM437 code page.\n" +
  39. " (cannot be used with -utf8 option)\n" +
  40. " -C bzip|deflate|none - use BZip2, Deflate, or No compression, for entries subsequently\n"+
  41. " added to the zip. The default is DEFLATE.\n"+
  42. " -d <path> - use the given directory path in the archive for\n" +
  43. " succeeding items added to the archive.\n" +
  44. " -D <path> - find files in the given directory on disk.\n" +
  45. " -e[s|r|q|a] - when there is an error reading a file to be zipped, either skip\n" +
  46. " the file, retry, quit, or ask the user what to do.\n"+
  47. " -E <selector> - a file selection expression. Examples: \n" +
  48. " *.txt \n" +
  49. " (name = *.txt) OR (name = *.xml) \n" +
  50. " (attrs = H) OR (name != *.xml) \n" +
  51. " (ctime < 2009/02/28-10:20:00) \n" +
  52. " (size > 1g) AND (mtime < 2009-12-10) \n" +
  53. " (ctime > 2009-04-29) AND (size < 10kb) \n" +
  54. " Filenames can include full paths. You must surround a filename \n" +
  55. " that includes spaces with single quotes.\n" +
  56. " -j- - do not traverse NTFS junctions\n" +
  57. " -j+ - traverse NTFS junctions (default)\n" +
  58. " -L <level> - compression level, 0..9 (Default is 6).\n" +
  59. " This applies only if using DEFLATE compression, the default.\n" +
  60. " -p <password> - apply the specified password for all succeeding files added.\n" +
  61. " use \"\" to reset the password to nil.\n" +
  62. " -progress - emit progress reports (good when creating large zips)\n" +
  63. " -r- - don't recurse directories (default).\n" +
  64. " -r+ - recurse directories.\n" +
  65. " -s <entry> 'string' - insert an entry of the given name into the \n" +
  66. " archive, with the given string as its content.\n" +
  67. " -sfx [w|c] - create a self-extracting archive, either a Windows or console app.\n" +
  68. " (cannot be used with -split)\n"+
  69. " -split <maxsize> - produce a split zip, with the specified maximum size. You can\n" +
  70. " optionally use kb or mb as a suffix to the size. \n" +
  71. " (-split cannot be used with -sfx).\n" +
  72. " -Tw+ - store Windows-format extended times (default).\n" +
  73. " -Tw- - don't store Windows-format extended times.\n" +
  74. " -Tu+ - store Unix-format extended times.\n" +
  75. " -Tu- - don't store Unix-format extended times (default).\n" +
  76. " -UTnow - use the same date/time, NOW, for all entries. \n" +
  77. " -UTnewest - use the same date/time, same as newest entry, for all entries. \n" +
  78. " -UToldest - use the same date/time, equal to oldest entry, for all entries. \n" +
  79. " -UT <datetime> - use the same date/time, as specified, for all entries. \n" +
  80. " -utf8 - use UTF-8 encoding for entry filenames and comments,\n" +
  81. " instead of the the default IBM437 code page.\n" +
  82. " (cannot be used with -cp option)\n" +
  83. " -zc <comment> - use the given comment for the archive.\n";
  84. Console.WriteLine(UsageMessage,
  85. System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());
  86. Environment.Exit(1);
  87. }
  88. static bool justHadByteUpdate= false;
  89. static bool isCanceled= false;
  90. static bool wantProgressReports = false;
  91. private static void SaveProgress(object sender, SaveProgressEventArgs e)
  92. {
  93. if (isCanceled)
  94. {
  95. e.Cancel = true;
  96. return;
  97. }
  98. if (!wantProgressReports) return;
  99. switch(e.EventType)
  100. {
  101. case ZipProgressEventType.Saving_Started:
  102. Console.WriteLine("Saving: {0}", e.ArchiveName);
  103. break;
  104. case ZipProgressEventType.Saving_Completed:
  105. justHadByteUpdate= false;
  106. Console.WriteLine();
  107. Console.WriteLine("Done: {0}", e.ArchiveName);
  108. break;
  109. case ZipProgressEventType.Saving_BeforeWriteEntry:
  110. if (justHadByteUpdate)
  111. Console.WriteLine();
  112. Console.WriteLine(" Writing: {0} ({1}/{2})",
  113. e.CurrentEntry.FileName, e.EntriesSaved+1, e.EntriesTotal);
  114. justHadByteUpdate= false;
  115. break;
  116. case ZipProgressEventType.Saving_AfterWriteEntry:
  117. break;
  118. case ZipProgressEventType.Saving_EntryBytesRead:
  119. if (justHadByteUpdate)
  120. Console.SetCursorPosition(0, Console.CursorTop);
  121. Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer,
  122. e.BytesTransferred / (0.01 * e.TotalBytesToTransfer ));
  123. justHadByteUpdate= true;
  124. break;
  125. }
  126. }
  127. // Ask the user what he wants to do
  128. public static void ZipError(object sender, ZipErrorEventArgs e)
  129. {
  130. Console.WriteLine("Error reading {0}...", e.FileName);
  131. Console.WriteLine(" Exception: {0}...", e.Exception);
  132. ZipEntry entry = e.CurrentEntry;
  133. string response = null;
  134. do
  135. {
  136. Console.Write("Retry, Skip, or Quit ? (R/S/Q) ");
  137. response = Console.ReadLine();
  138. Console.WriteLine();
  139. } while (response != null &&
  140. response[0]!='S' && response[0]!='s' &&
  141. response[0]!='R' && response[0]!='r' &&
  142. response[0]!='Q' && response[0]!='q');
  143. e.Cancel = (response[0]=='Q' || response[0]=='q');
  144. if (response[0]=='S' || response[0]=='s')
  145. entry.ZipErrorAction = ZipErrorAction.Skip;
  146. else if (response[0]=='R' || response[0]=='r')
  147. entry.ZipErrorAction = ZipErrorAction.Retry;
  148. }
  149. static void CtrlC_Handler(object sender, ConsoleCancelEventArgs args)
  150. {
  151. isCanceled = true;
  152. Console.WriteLine("\nCtrl-C");
  153. //cleanupCompleted.WaitOne();
  154. // prevent the process from exiting until cleanup is done:
  155. args.Cancel = true;
  156. }
  157. public static void Main(String[] args)
  158. {
  159. bool saveToStdout = false;
  160. if (args.Length < 2) Usage();
  161. if (args[0]=="-")
  162. {
  163. saveToStdout = true;
  164. }
  165. else if (File.Exists(args[0]))
  166. {
  167. System.Console.WriteLine("That zip file ({0}) already exists.", args[0]);
  168. }
  169. // Because the comments and filenames on zip entries may be UTF-8
  170. // System.Console.OutputEncoding = new System.Text.UTF8Encoding();
  171. Console.CancelKeyPress += CtrlC_Handler;
  172. try
  173. {
  174. Nullable<SelfExtractorFlavor> flavor = null;
  175. int codePage = 0;
  176. ZipEntry e = null;
  177. int _UseUniformTimestamp = 0;
  178. DateTime _fixedTimestamp= System.DateTime.Now;
  179. string entryDirectoryPathInArchive = "";
  180. string directoryOnDisk = null;
  181. bool recurseDirectories = false;
  182. bool wantRecurse = false;
  183. string actualItem;
  184. // read/update an existing zip, or create a new one.
  185. using (ZipFile zip = new ZipFile(args[0]))
  186. {
  187. zip.StatusMessageTextWriter = System.Console.Out;
  188. zip.SaveProgress += SaveProgress;
  189. for (int i = 1; i < args.Length; i++)
  190. {
  191. switch (args[i])
  192. {
  193. case "-es":
  194. zip.ZipErrorAction = ZipErrorAction.Skip;
  195. break;
  196. case "-er":
  197. zip.ZipErrorAction = ZipErrorAction.Retry;
  198. break;
  199. case "-eq":
  200. zip.ZipErrorAction = ZipErrorAction.Throw;
  201. break;
  202. case "-ea":
  203. zip.ZipError += ZipError;
  204. break;
  205. case "-64":
  206. zip.UseZip64WhenSaving = Zip64Option.Always;
  207. break;
  208. case "-aes":
  209. zip.Encryption = EncryptionAlgorithm.WinZipAes256;
  210. break;
  211. case "-C":
  212. i++;
  213. if (args.Length <= i) Usage();
  214. switch(args[i].ToLower())
  215. {
  216. case "b":
  217. case "bzip":
  218. case "bzip2":
  219. zip.CompressionMethod = CompressionMethod.BZip2;
  220. break;
  221. case "d":
  222. case "deflate":
  223. zip.CompressionMethod = CompressionMethod.Deflate;
  224. break;
  225. case "n":
  226. case "none":
  227. zip.CompressionMethod = CompressionMethod.None;
  228. break;
  229. default:
  230. Usage();
  231. break;
  232. }
  233. break;
  234. case "-cp":
  235. i++;
  236. if (args.Length <= i) Usage();
  237. System.Int32.TryParse(args[i], out codePage);
  238. if (codePage != 0)
  239. {
  240. zip.AlternateEncoding = System.Text.Encoding.GetEncoding(codePage);
  241. zip.AlternateEncodingUsage = ZipOption.Always;
  242. }
  243. break;
  244. case "-d":
  245. i++;
  246. if (args.Length <= i) Usage();
  247. entryDirectoryPathInArchive = args[i];
  248. break;
  249. case "-D":
  250. i++;
  251. if (args.Length <= i) Usage();
  252. directoryOnDisk = args[i];
  253. break;
  254. case "-E":
  255. i++;
  256. if (args.Length <= i) Usage();
  257. wantRecurse = recurseDirectories || args[i].Contains("\\");
  258. // Console.WriteLine("spec({0})", args[i]);
  259. // Console.WriteLine("dir({0})", directoryOnDisk);
  260. // Console.WriteLine("dirInArc({0})", entryDirectoryPathInArchive);
  261. // Console.WriteLine("recurse({0})", recurseDirectories);
  262. zip.UpdateSelectedFiles(args[i],
  263. directoryOnDisk,
  264. entryDirectoryPathInArchive,
  265. wantRecurse);
  266. break;
  267. case "-j-":
  268. zip.AddDirectoryWillTraverseReparsePoints = false;
  269. break;
  270. case "-j+":
  271. zip.AddDirectoryWillTraverseReparsePoints = true;
  272. break;
  273. case "-L":
  274. i++;
  275. if (args.Length <= i) Usage();
  276. zip.CompressionLevel = (Ionic.Zlib.CompressionLevel)
  277. System.Int32.Parse(args[i]);
  278. break;
  279. case "-p":
  280. i++;
  281. if (args.Length <= i) Usage();
  282. zip.Password = (args[i] == "") ? null : args[i];
  283. break;
  284. case "-progress":
  285. wantProgressReports = true;
  286. break;
  287. case "-r-":
  288. recurseDirectories = false;
  289. break;
  290. case "-r+":
  291. recurseDirectories = true;
  292. break;
  293. case "-s":
  294. i++;
  295. if (args.Length <= i) Usage();
  296. string entryName = args[i];
  297. i++;
  298. if (args.Length <= i) Usage();
  299. string content = args[i];
  300. e = zip.AddEntry(Path.Combine(entryDirectoryPathInArchive, entryName), content);
  301. // if (entryComment != null)
  302. // {
  303. // e.Comment = entryComment;
  304. // entryComment = null;
  305. // }
  306. break;
  307. case "-sfx":
  308. i++;
  309. if (args.Length <= i) Usage();
  310. if (args[i] != "w" && args[i] != "c") Usage();
  311. flavor = new Nullable<SelfExtractorFlavor>
  312. ((args[i] == "w") ? SelfExtractorFlavor.WinFormsApplication : SelfExtractorFlavor.ConsoleApplication);
  313. break;
  314. case "-split":
  315. i++;
  316. if (args.Length <= i) Usage();
  317. if (args[i].EndsWith("K") || args[i].EndsWith("k"))
  318. zip.MaxOutputSegmentSize = Int32.Parse(args[i].Substring(0, args[i].Length - 1)) * 1024;
  319. else if (args[i].EndsWith("M") || args[i].EndsWith("m"))
  320. zip.MaxOutputSegmentSize = Int32.Parse(args[i].Substring(0, args[i].Length - 1)) * 1024 * 1024;
  321. else
  322. zip.MaxOutputSegmentSize = Int32.Parse(args[i]);
  323. break;
  324. case "-Tw+":
  325. zip.EmitTimesInWindowsFormatWhenSaving = true;
  326. break;
  327. case "-Tw-":
  328. zip.EmitTimesInWindowsFormatWhenSaving = false;
  329. break;
  330. case "-Tu+":
  331. zip.EmitTimesInUnixFormatWhenSaving = true;
  332. break;
  333. case "-Tu-":
  334. zip.EmitTimesInUnixFormatWhenSaving = false;
  335. break;
  336. case "-UTnow":
  337. _UseUniformTimestamp = 1;
  338. _fixedTimestamp = System.DateTime.UtcNow;
  339. break;
  340. case "-UTnewest":
  341. _UseUniformTimestamp = 2;
  342. break;
  343. case "-UToldest":
  344. _UseUniformTimestamp = 3;
  345. break;
  346. case "-UT":
  347. i++;
  348. if (args.Length <= i) Usage();
  349. _UseUniformTimestamp = 4;
  350. try
  351. {
  352. _fixedTimestamp= System.DateTime.Parse(args[i]);
  353. }
  354. catch
  355. {
  356. throw new ArgumentException("-UT");
  357. }
  358. break;
  359. case "-utf8":
  360. zip.AlternateEncoding = System.Text.Encoding.UTF8;
  361. zip.AlternateEncodingUsage = ZipOption.Always;
  362. break;
  363. #if NOT
  364. case "-c":
  365. i++;
  366. if (args.Length <= i) Usage();
  367. entryComment = args[i]; // for the next entry
  368. break;
  369. #endif
  370. case "-zc":
  371. i++;
  372. if (args.Length <= i) Usage();
  373. zip.Comment = args[i];
  374. break;
  375. default:
  376. // UpdateItem will add Files or Dirs,
  377. // recurses subdirectories
  378. actualItem = Path.Combine(directoryOnDisk ?? ".", args[i]);
  379. zip.UpdateItem(actualItem, entryDirectoryPathInArchive);
  380. break;
  381. }
  382. }
  383. if (_UseUniformTimestamp > 0)
  384. {
  385. if (_UseUniformTimestamp==2)
  386. {
  387. // newest
  388. _fixedTimestamp = new System.DateTime(1601,1,1,0,0,0);
  389. foreach(var entry in zip)
  390. {
  391. if (entry.LastModified > _fixedTimestamp)
  392. _fixedTimestamp = entry.LastModified;
  393. }
  394. }
  395. else if (_UseUniformTimestamp==3)
  396. {
  397. // oldest
  398. foreach(var entry in zip)
  399. {
  400. if (entry.LastModified < _fixedTimestamp)
  401. _fixedTimestamp = entry.LastModified;
  402. }
  403. }
  404. foreach(var entry in zip)
  405. {
  406. entry.LastModified = _fixedTimestamp;
  407. }
  408. }
  409. if (!flavor.HasValue)
  410. {
  411. if (saveToStdout)
  412. zip.Save(Console.OpenStandardOutput());
  413. else
  414. zip.Save();
  415. }
  416. else
  417. {
  418. if (saveToStdout)
  419. throw new Exception("Cannot save SFX to stdout, sorry! See http://dotnetzip.codeplex.com/WorkItem/View.aspx?WorkItemId=7246");
  420. zip.SaveSelfExtractor(args[0], flavor.Value);
  421. }
  422. }
  423. }
  424. catch (System.Exception ex1)
  425. {
  426. System.Console.WriteLine("Exception: " + ex1);
  427. }
  428. }
  429. }
  430. }