ZipFile.Selector.cs 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  1. // ZipFile.Selector.cs
  2. // ------------------------------------------------------------------
  3. //
  4. // Copyright (c) 2009-2010 Dino Chiesa.
  5. // All rights reserved.
  6. //
  7. // This code module is part of DotNetZip, a zipfile class library.
  8. //
  9. // ------------------------------------------------------------------
  10. //
  11. // This code is licensed under the Microsoft Public License.
  12. // See the file License.txt for the license details.
  13. // More info on: http://dotnetzip.codeplex.com
  14. //
  15. // ------------------------------------------------------------------
  16. //
  17. // last saved (in emacs):
  18. // Time-stamp: <2011-August-06 09:35:58>
  19. //
  20. // ------------------------------------------------------------------
  21. //
  22. // This module defines methods in the ZipFile class associated to the FileFilter
  23. // capability - selecting files to add into the archive, or selecting entries to
  24. // retrieve from the archive based on criteria including the filename, size, date, or
  25. // attributes. It is something like a "poor man's LINQ". I included it into DotNetZip
  26. // because not everyone has .NET 3.5 yet. When using DotNetZip on .NET 3.5, the LINQ
  27. // query/selection will be superior.
  28. //
  29. // These methods are segregated into a different module to facilitate easy exclusion for
  30. // those people who wish to have a smaller library without this function.
  31. //
  32. // ------------------------------------------------------------------
  33. using System;
  34. using System.IO;
  35. using System.Collections.Generic;
  36. namespace Ionic.Zip
  37. {
  38. partial class ZipFile
  39. {
  40. /// <summary>
  41. /// Adds to the ZipFile a set of files from the current working directory on
  42. /// disk, that conform to the specified criteria.
  43. /// </summary>
  44. ///
  45. /// <remarks>
  46. /// <para>
  47. /// This method selects files from the the current working directory matching
  48. /// the specified criteria, and adds them to the ZipFile.
  49. /// </para>
  50. ///
  51. /// <para>
  52. /// Specify the criteria in statements of 3 elements: a noun, an operator, and
  53. /// a value. Consider the string "name != *.doc" . The noun is "name". The
  54. /// operator is "!=", implying "Not Equal". The value is "*.doc". That
  55. /// criterion, in English, says "all files with a name that does not end in
  56. /// the .doc extension."
  57. /// </para>
  58. ///
  59. /// <para>
  60. /// Supported nouns include "name" (or "filename") for the filename; "atime",
  61. /// "mtime", and "ctime" for last access time, last modfied time, and created
  62. /// time of the file, respectively; "attributes" (or "attrs") for the file
  63. /// attributes; "size" (or "length") for the file length (uncompressed), and
  64. /// "type" for the type of object, either a file or a directory. The
  65. /// "attributes", "name" and "type" nouns both support = and != as operators.
  66. /// The "size", "atime", "mtime", and "ctime" nouns support = and !=, and
  67. /// &gt;, &gt;=, &lt;, &lt;= as well. The times are taken to be expressed in
  68. /// local time.
  69. /// </para>
  70. ///
  71. /// <para>
  72. /// Specify values for the file attributes as a string with one or more of the
  73. /// characters H,R,S,A,I,L in any order, implying file attributes of Hidden,
  74. /// ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint (symbolic
  75. /// link) respectively.
  76. /// </para>
  77. ///
  78. /// <para>
  79. /// To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as the
  80. /// format. If you omit the HH:mm:ss portion, it is assumed to be 00:00:00
  81. /// (midnight).
  82. /// </para>
  83. ///
  84. /// <para>
  85. /// The value for a size criterion is expressed in integer quantities of bytes,
  86. /// kilobytes (use k or kb after the number), megabytes (m or mb), or gigabytes
  87. /// (g or gb).
  88. /// </para>
  89. ///
  90. /// <para>
  91. /// The value for a name is a pattern to match against the filename, potentially
  92. /// including wildcards. The pattern follows CMD.exe glob rules: * implies one
  93. /// or more of any character, while ? implies one character. If the name
  94. /// pattern contains any slashes, it is matched to the entire filename,
  95. /// including the path; otherwise, it is matched against only the filename
  96. /// without the path. This means a pattern of "*\*.*" matches all files one
  97. /// directory level deep, while a pattern of "*.*" matches all files in all
  98. /// directories.
  99. /// </para>
  100. ///
  101. /// <para>
  102. /// To specify a name pattern that includes spaces, use single quotes around the
  103. /// pattern. A pattern of "'* *.*'" will match all files that have spaces in
  104. /// the filename. The full criteria string for that would be "name = '* *.*'" .
  105. /// </para>
  106. ///
  107. /// <para>
  108. /// The value for a type criterion is either F (implying a file) or D (implying
  109. /// a directory).
  110. /// </para>
  111. ///
  112. /// <para>
  113. /// Some examples:
  114. /// </para>
  115. ///
  116. /// <list type="table">
  117. /// <listheader>
  118. /// <term>criteria</term>
  119. /// <description>Files retrieved</description>
  120. /// </listheader>
  121. ///
  122. /// <item>
  123. /// <term>name != *.xls </term>
  124. /// <description>any file with an extension that is not .xls
  125. /// </description>
  126. /// </item>
  127. ///
  128. /// <item>
  129. /// <term>name = *.mp3 </term>
  130. /// <description>any file with a .mp3 extension.
  131. /// </description>
  132. /// </item>
  133. ///
  134. /// <item>
  135. /// <term>*.mp3</term>
  136. /// <description>(same as above) any file with a .mp3 extension.
  137. /// </description>
  138. /// </item>
  139. ///
  140. /// <item>
  141. /// <term>attributes = A </term>
  142. /// <description>all files whose attributes include the Archive bit.
  143. /// </description>
  144. /// </item>
  145. ///
  146. /// <item>
  147. /// <term>attributes != H </term>
  148. /// <description>all files whose attributes do not include the Hidden bit.
  149. /// </description>
  150. /// </item>
  151. ///
  152. /// <item>
  153. /// <term>mtime > 2009-01-01</term>
  154. /// <description>all files with a last modified time after January 1st, 2009.
  155. /// </description>
  156. /// </item>
  157. ///
  158. /// <item>
  159. /// <term>size > 2gb</term>
  160. /// <description>all files whose uncompressed size is greater than 2gb.
  161. /// </description>
  162. /// </item>
  163. ///
  164. /// <item>
  165. /// <term>type = D</term>
  166. /// <description>all directories in the filesystem. </description>
  167. /// </item>
  168. ///
  169. /// </list>
  170. ///
  171. /// <para>
  172. /// You can combine criteria with the conjunctions AND or OR. Using a string
  173. /// like "name = *.txt AND size &gt;= 100k" for the selectionCriteria retrieves
  174. /// entries whose names end in .txt, and whose uncompressed size is greater than
  175. /// or equal to 100 kilobytes.
  176. /// </para>
  177. ///
  178. /// <para>
  179. /// For more complex combinations of criteria, you can use parenthesis to group
  180. /// clauses in the boolean logic. Without parenthesis, the precedence of the
  181. /// criterion atoms is determined by order of appearance. Unlike the C#
  182. /// language, the AND conjunction does not take precendence over the logical OR.
  183. /// This is important only in strings that contain 3 or more criterion atoms.
  184. /// In other words, "name = *.txt and size &gt; 1000 or attributes = H" implies
  185. /// "((name = *.txt AND size &gt; 1000) OR attributes = H)" while "attributes =
  186. /// H OR name = *.txt and size &gt; 1000" evaluates to "((attributes = H OR name
  187. /// = *.txt) AND size &gt; 1000)". When in doubt, use parenthesis.
  188. /// </para>
  189. ///
  190. /// <para>
  191. /// Using time properties requires some extra care. If you want to retrieve all
  192. /// entries that were last updated on 2009 February 14, specify a time range
  193. /// like so:"mtime &gt;= 2009-02-14 AND mtime &lt; 2009-02-15". Read this to
  194. /// say: all files updated after 12:00am on February 14th, until 12:00am on
  195. /// February 15th. You can use the same bracketing approach to specify any time
  196. /// period - a year, a month, a week, and so on.
  197. /// </para>
  198. ///
  199. /// <para>
  200. /// The syntax allows one special case: if you provide a string with no spaces, it is
  201. /// treated as a pattern to match for the filename. Therefore a string like "*.xls"
  202. /// will be equivalent to specifying "name = *.xls".
  203. /// </para>
  204. ///
  205. /// <para>
  206. /// There is no logic in this method that insures that the file inclusion
  207. /// criteria are internally consistent. For example, it's possible to specify
  208. /// criteria that says the file must have a size of less than 100 bytes, as well
  209. /// as a size that is greater than 1000 bytes. Obviously no file will ever
  210. /// satisfy such criteria, but this method does not detect such logical
  211. /// inconsistencies. The caller is responsible for insuring the criteria are
  212. /// sensible.
  213. /// </para>
  214. ///
  215. /// <para>
  216. /// Using this method, the file selection does not recurse into
  217. /// subdirectories, and the full path of the selected files is included in the
  218. /// entries added into the zip archive. If you don't like these behaviors,
  219. /// see the other overloads of this method.
  220. /// </para>
  221. /// </remarks>
  222. ///
  223. /// <example>
  224. /// This example zips up all *.csv files in the current working directory.
  225. /// <code>
  226. /// using (ZipFile zip = new ZipFile())
  227. /// {
  228. /// // To just match on filename wildcards,
  229. /// // use the shorthand form of the selectionCriteria string.
  230. /// zip.AddSelectedFiles("*.csv");
  231. /// zip.Save(PathToZipArchive);
  232. /// }
  233. /// </code>
  234. /// <code lang="VB">
  235. /// Using zip As ZipFile = New ZipFile()
  236. /// zip.AddSelectedFiles("*.csv")
  237. /// zip.Save(PathToZipArchive)
  238. /// End Using
  239. /// </code>
  240. /// </example>
  241. ///
  242. /// <param name="selectionCriteria">The criteria for file selection</param>
  243. public void AddSelectedFiles(String selectionCriteria)
  244. {
  245. this.AddSelectedFiles(selectionCriteria, ".", null, false);
  246. }
  247. /// <summary>
  248. /// Adds to the ZipFile a set of files from the disk that conform to the
  249. /// specified criteria, optionally recursing into subdirectories.
  250. /// </summary>
  251. ///
  252. /// <remarks>
  253. /// <para>
  254. /// This method selects files from the the current working directory matching
  255. /// the specified criteria, and adds them to the ZipFile. If
  256. /// <c>recurseDirectories</c> is true, files are also selected from
  257. /// subdirectories, and the directory structure in the filesystem is
  258. /// reproduced in the zip archive, rooted at the current working directory.
  259. /// </para>
  260. ///
  261. /// <para>
  262. /// Using this method, the full path of the selected files is included in the
  263. /// entries added into the zip archive. If you don't want this behavior, use
  264. /// one of the overloads of this method that allows the specification of a
  265. /// <c>directoryInArchive</c>.
  266. /// </para>
  267. ///
  268. /// <para>
  269. /// For details on the syntax for the selectionCriteria parameter, see <see
  270. /// cref="AddSelectedFiles(String)"/>.
  271. /// </para>
  272. ///
  273. /// </remarks>
  274. ///
  275. /// <example>
  276. ///
  277. /// This example zips up all *.xml files in the current working directory, or any
  278. /// subdirectory, that are larger than 1mb.
  279. ///
  280. /// <code>
  281. /// using (ZipFile zip = new ZipFile())
  282. /// {
  283. /// // Use a compound expression in the selectionCriteria string.
  284. /// zip.AddSelectedFiles("name = *.xml and size > 1024kb", true);
  285. /// zip.Save(PathToZipArchive);
  286. /// }
  287. /// </code>
  288. /// <code lang="VB">
  289. /// Using zip As ZipFile = New ZipFile()
  290. /// ' Use a compound expression in the selectionCriteria string.
  291. /// zip.AddSelectedFiles("name = *.xml and size > 1024kb", true)
  292. /// zip.Save(PathToZipArchive)
  293. /// End Using
  294. /// </code>
  295. /// </example>
  296. ///
  297. /// <param name="selectionCriteria">The criteria for file selection</param>
  298. ///
  299. /// <param name="recurseDirectories">
  300. /// If true, the file selection will recurse into subdirectories.
  301. /// </param>
  302. public void AddSelectedFiles(String selectionCriteria, bool recurseDirectories)
  303. {
  304. this.AddSelectedFiles(selectionCriteria, ".", null, recurseDirectories);
  305. }
  306. /// <summary>
  307. /// Adds to the ZipFile a set of files from a specified directory in the
  308. /// filesystem, that conform to the specified criteria.
  309. /// </summary>
  310. ///
  311. /// <remarks>
  312. /// <para>
  313. /// This method selects files that conform to the specified criteria, from the
  314. /// the specified directory on disk, and adds them to the ZipFile. The search
  315. /// does not recurse into subdirectores.
  316. /// </para>
  317. ///
  318. /// <para>
  319. /// Using this method, the full filesystem path of the files on disk is
  320. /// reproduced on the entries added to the zip file. If you don't want this
  321. /// behavior, use one of the other overloads of this method.
  322. /// </para>
  323. ///
  324. /// <para>
  325. /// For details on the syntax for the selectionCriteria parameter, see <see
  326. /// cref="AddSelectedFiles(String)"/>.
  327. /// </para>
  328. ///
  329. /// </remarks>
  330. ///
  331. /// <example>
  332. ///
  333. /// This example zips up all *.xml files larger than 1mb in the directory
  334. /// given by "d:\rawdata".
  335. ///
  336. /// <code>
  337. /// using (ZipFile zip = new ZipFile())
  338. /// {
  339. /// // Use a compound expression in the selectionCriteria string.
  340. /// zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\\rawdata");
  341. /// zip.Save(PathToZipArchive);
  342. /// }
  343. /// </code>
  344. ///
  345. /// <code lang="VB">
  346. /// Using zip As ZipFile = New ZipFile()
  347. /// ' Use a compound expression in the selectionCriteria string.
  348. /// zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\rawdata)
  349. /// zip.Save(PathToZipArchive)
  350. /// End Using
  351. /// </code>
  352. /// </example>
  353. ///
  354. /// <param name="selectionCriteria">The criteria for file selection</param>
  355. ///
  356. /// <param name="directoryOnDisk">
  357. /// The name of the directory on the disk from which to select files.
  358. /// </param>
  359. public void AddSelectedFiles(String selectionCriteria, String directoryOnDisk)
  360. {
  361. this.AddSelectedFiles(selectionCriteria, directoryOnDisk, null, false);
  362. }
  363. /// <summary>
  364. /// Adds to the ZipFile a set of files from the specified directory on disk,
  365. /// that conform to the specified criteria.
  366. /// </summary>
  367. ///
  368. /// <remarks>
  369. ///
  370. /// <para>
  371. /// This method selects files from the the specified disk directory matching
  372. /// the specified selection criteria, and adds them to the ZipFile. If
  373. /// <c>recurseDirectories</c> is true, files are also selected from
  374. /// subdirectories.
  375. /// </para>
  376. ///
  377. /// <para>
  378. /// The full directory structure in the filesystem is reproduced on the
  379. /// entries added to the zip archive. If you don't want this behavior, use
  380. /// one of the overloads of this method that allows the specification of a
  381. /// <c>directoryInArchive</c>.
  382. /// </para>
  383. ///
  384. /// <para>
  385. /// For details on the syntax for the selectionCriteria parameter, see <see
  386. /// cref="AddSelectedFiles(String)"/>.
  387. /// </para>
  388. /// </remarks>
  389. ///
  390. /// <example>
  391. ///
  392. /// This example zips up all *.csv files in the "files" directory, or any
  393. /// subdirectory, that have been saved since 2009 February 14th.
  394. ///
  395. /// <code>
  396. /// using (ZipFile zip = new ZipFile())
  397. /// {
  398. /// // Use a compound expression in the selectionCriteria string.
  399. /// zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true);
  400. /// zip.Save(PathToZipArchive);
  401. /// }
  402. /// </code>
  403. /// <code lang="VB">
  404. /// Using zip As ZipFile = New ZipFile()
  405. /// ' Use a compound expression in the selectionCriteria string.
  406. /// zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true)
  407. /// zip.Save(PathToZipArchive)
  408. /// End Using
  409. /// </code>
  410. /// </example>
  411. ///
  412. /// <example>
  413. /// This example zips up all files in the current working
  414. /// directory, and all its child directories, except those in
  415. /// the <c>excludethis</c> subdirectory.
  416. /// <code lang="VB">
  417. /// Using Zip As ZipFile = New ZipFile(zipfile)
  418. /// Zip.AddSelectedFfiles("name != 'excludethis\*.*'", datapath, True)
  419. /// Zip.Save()
  420. /// End Using
  421. /// </code>
  422. /// </example>
  423. ///
  424. /// <param name="selectionCriteria">The criteria for file selection</param>
  425. ///
  426. /// <param name="directoryOnDisk">
  427. /// The filesystem path from which to select files.
  428. /// </param>
  429. ///
  430. /// <param name="recurseDirectories">
  431. /// If true, the file selection will recurse into subdirectories.
  432. /// </param>
  433. public void AddSelectedFiles(String selectionCriteria, String directoryOnDisk, bool recurseDirectories)
  434. {
  435. this.AddSelectedFiles(selectionCriteria, directoryOnDisk, null, recurseDirectories);
  436. }
  437. /// <summary>
  438. /// Adds to the ZipFile a selection of files from the specified directory on
  439. /// disk, that conform to the specified criteria, and using a specified root
  440. /// path for entries added to the zip archive.
  441. /// </summary>
  442. ///
  443. /// <remarks>
  444. /// <para>
  445. /// This method selects files from the specified disk directory matching the
  446. /// specified selection criteria, and adds those files to the ZipFile, using
  447. /// the specified directory path in the archive. The search does not recurse
  448. /// into subdirectories. For details on the syntax for the selectionCriteria
  449. /// parameter, see <see cref="AddSelectedFiles(String)" />.
  450. /// </para>
  451. ///
  452. /// </remarks>
  453. ///
  454. /// <example>
  455. ///
  456. /// This example zips up all *.psd files in the "photos" directory that have
  457. /// been saved since 2009 February 14th, and puts them all in a zip file,
  458. /// using the directory name of "content" in the zip archive itself. When the
  459. /// zip archive is unzipped, the folder containing the .psd files will be
  460. /// named "content".
  461. ///
  462. /// <code>
  463. /// using (ZipFile zip = new ZipFile())
  464. /// {
  465. /// // Use a compound expression in the selectionCriteria string.
  466. /// zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content");
  467. /// zip.Save(PathToZipArchive);
  468. /// }
  469. /// </code>
  470. /// <code lang="VB">
  471. /// Using zip As ZipFile = New ZipFile
  472. /// zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content")
  473. /// zip.Save(PathToZipArchive)
  474. /// End Using
  475. /// </code>
  476. /// </example>
  477. ///
  478. /// <param name="selectionCriteria">
  479. /// The criteria for selection of files to add to the <c>ZipFile</c>.
  480. /// </param>
  481. ///
  482. /// <param name="directoryOnDisk">
  483. /// The path to the directory in the filesystem from which to select files.
  484. /// </param>
  485. ///
  486. /// <param name="directoryPathInArchive">
  487. /// Specifies a directory path to use to in place of the
  488. /// <c>directoryOnDisk</c>. This path may, or may not, correspond to a real
  489. /// directory in the current filesystem. If the files within the zip are
  490. /// later extracted, this is the path used for the extracted file. Passing
  491. /// null (nothing in VB) will use the path on the file name, if any; in other
  492. /// words it would use <c>directoryOnDisk</c>, plus any subdirectory. Passing
  493. /// the empty string ("") will insert the item at the root path within the
  494. /// archive.
  495. /// </param>
  496. public void AddSelectedFiles(String selectionCriteria,
  497. String directoryOnDisk,
  498. String directoryPathInArchive)
  499. {
  500. this.AddSelectedFiles(selectionCriteria, directoryOnDisk, directoryPathInArchive, false);
  501. }
  502. /// <summary>
  503. /// Adds to the ZipFile a selection of files from the specified directory on
  504. /// disk, that conform to the specified criteria, optionally recursing through
  505. /// subdirectories, and using a specified root path for entries added to the
  506. /// zip archive.
  507. /// </summary>
  508. ///
  509. /// <remarks>
  510. /// This method selects files from the specified disk directory that match the
  511. /// specified selection criteria, and adds those files to the ZipFile, using
  512. /// the specified directory path in the archive. If <c>recurseDirectories</c>
  513. /// is true, files are also selected from subdirectories, and the directory
  514. /// structure in the filesystem is reproduced in the zip archive, rooted at
  515. /// the directory specified by <c>directoryOnDisk</c>. For details on the
  516. /// syntax for the selectionCriteria parameter, see <see
  517. /// cref="AddSelectedFiles(String)" />.
  518. /// </remarks>
  519. ///
  520. /// <example>
  521. ///
  522. /// This example zips up all files that are NOT *.pst files, in the current
  523. /// working directory and any subdirectories.
  524. ///
  525. /// <code>
  526. /// using (ZipFile zip = new ZipFile())
  527. /// {
  528. /// zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true);
  529. /// zip.Save(PathToZipArchive);
  530. /// }
  531. /// </code>
  532. /// <code lang="VB">
  533. /// Using zip As ZipFile = New ZipFile
  534. /// zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true)
  535. /// zip.Save(PathToZipArchive)
  536. /// End Using
  537. /// </code>
  538. /// </example>
  539. ///
  540. /// <param name="selectionCriteria">
  541. /// The criteria for selection of files to add to the <c>ZipFile</c>.
  542. /// </param>
  543. ///
  544. /// <param name="directoryOnDisk">
  545. /// The path to the directory in the filesystem from which to select files.
  546. /// </param>
  547. ///
  548. /// <param name="directoryPathInArchive">
  549. /// Specifies a directory path to use to in place of the
  550. /// <c>directoryOnDisk</c>. This path may, or may not, correspond to a real
  551. /// directory in the current filesystem. If the files within the zip are
  552. /// later extracted, this is the path used for the extracted file. Passing
  553. /// null (nothing in VB) will use the path on the file name, if any; in other
  554. /// words it would use <c>directoryOnDisk</c>, plus any subdirectory. Passing
  555. /// the empty string ("") will insert the item at the root path within the
  556. /// archive.
  557. /// </param>
  558. ///
  559. /// <param name="recurseDirectories">
  560. /// If true, the method also scans subdirectories for files matching the
  561. /// criteria.
  562. /// </param>
  563. public void AddSelectedFiles(String selectionCriteria,
  564. String directoryOnDisk,
  565. String directoryPathInArchive,
  566. bool recurseDirectories)
  567. {
  568. _AddOrUpdateSelectedFiles(selectionCriteria,
  569. directoryOnDisk,
  570. directoryPathInArchive,
  571. recurseDirectories,
  572. false);
  573. }
  574. /// <summary>
  575. /// Updates the ZipFile with a selection of files from the disk that conform
  576. /// to the specified criteria.
  577. /// </summary>
  578. ///
  579. /// <remarks>
  580. /// This method selects files from the specified disk directory that match the
  581. /// specified selection criteria, and Updates the <c>ZipFile</c> with those
  582. /// files, using the specified directory path in the archive. If
  583. /// <c>recurseDirectories</c> is true, files are also selected from
  584. /// subdirectories, and the directory structure in the filesystem is
  585. /// reproduced in the zip archive, rooted at the directory specified by
  586. /// <c>directoryOnDisk</c>. For details on the syntax for the
  587. /// selectionCriteria parameter, see <see cref="AddSelectedFiles(String)" />.
  588. /// </remarks>
  589. ///
  590. /// <param name="selectionCriteria">
  591. /// The criteria for selection of files to add to the <c>ZipFile</c>.
  592. /// </param>
  593. ///
  594. /// <param name="directoryOnDisk">
  595. /// The path to the directory in the filesystem from which to select files.
  596. /// </param>
  597. ///
  598. /// <param name="directoryPathInArchive">
  599. /// Specifies a directory path to use to in place of the
  600. /// <c>directoryOnDisk</c>. This path may, or may not, correspond to a
  601. /// real directory in the current filesystem. If the files within the zip
  602. /// are later extracted, this is the path used for the extracted file.
  603. /// Passing null (nothing in VB) will use the path on the file name, if
  604. /// any; in other words it would use <c>directoryOnDisk</c>, plus any
  605. /// subdirectory. Passing the empty string ("") will insert the item at
  606. /// the root path within the archive.
  607. /// </param>
  608. ///
  609. /// <param name="recurseDirectories">
  610. /// If true, the method also scans subdirectories for files matching the criteria.
  611. /// </param>
  612. ///
  613. /// <seealso cref="AddSelectedFiles(String, String, String, bool)" />
  614. public void UpdateSelectedFiles(String selectionCriteria,
  615. String directoryOnDisk,
  616. String directoryPathInArchive,
  617. bool recurseDirectories)
  618. {
  619. _AddOrUpdateSelectedFiles(selectionCriteria,
  620. directoryOnDisk,
  621. directoryPathInArchive,
  622. recurseDirectories,
  623. true);
  624. }
  625. private string EnsureendInSlash(string s)
  626. {
  627. if (s.EndsWith("\\")) return s;
  628. return s + "\\";
  629. }
  630. private void _AddOrUpdateSelectedFiles(String selectionCriteria,
  631. String directoryOnDisk,
  632. String directoryPathInArchive,
  633. bool recurseDirectories,
  634. bool wantUpdate)
  635. {
  636. if (directoryOnDisk == null && (Directory.Exists(selectionCriteria)))
  637. {
  638. directoryOnDisk = selectionCriteria;
  639. selectionCriteria = "*.*";
  640. }
  641. else if (String.IsNullOrEmpty(directoryOnDisk))
  642. {
  643. directoryOnDisk = ".";
  644. }
  645. // workitem 9176
  646. while (directoryOnDisk.EndsWith("\\")) directoryOnDisk = directoryOnDisk.Substring(0, directoryOnDisk.Length - 1);
  647. if (Verbose) StatusMessageTextWriter.WriteLine("adding selection '{0}' from dir '{1}'...",
  648. selectionCriteria, directoryOnDisk);
  649. Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
  650. AddDirectoryWillTraverseReparsePoints);
  651. var itemsToAdd = ff.SelectFiles(directoryOnDisk, recurseDirectories);
  652. if (Verbose) StatusMessageTextWriter.WriteLine("found {0} files...", itemsToAdd.Count);
  653. OnAddStarted();
  654. AddOrUpdateAction action = (wantUpdate) ? AddOrUpdateAction.AddOrUpdate : AddOrUpdateAction.AddOnly;
  655. foreach (var item in itemsToAdd)
  656. {
  657. // workitem 10153
  658. string dirInArchive = (directoryPathInArchive == null)
  659. ? null
  660. // workitem 12260
  661. : ReplaceLeadingDirectory(Path.GetDirectoryName(item),
  662. directoryOnDisk,
  663. directoryPathInArchive);
  664. if (File.Exists(item))
  665. {
  666. if (wantUpdate)
  667. this.UpdateFile(item, dirInArchive);
  668. else
  669. this.AddFile(item, dirInArchive);
  670. }
  671. else
  672. {
  673. // this adds "just" the directory, without recursing to the contained files
  674. AddOrUpdateDirectoryImpl(item, dirInArchive, action, false, 0);
  675. }
  676. }
  677. OnAddCompleted();
  678. }
  679. // workitem 12260
  680. private static string ReplaceLeadingDirectory(string original,
  681. string pattern,
  682. string replacement)
  683. {
  684. string upperString = original.ToUpper();
  685. string upperPattern = pattern.ToUpper();
  686. int p1 = upperString.IndexOf(upperPattern);
  687. if (p1 != 0) return original;
  688. return replacement + original.Substring(upperPattern.Length);
  689. }
  690. #if NOT
  691. private static string ReplaceEx(string original,
  692. string pattern,
  693. string replacement)
  694. {
  695. int count, position0, position1;
  696. count = position0 = position1 = 0;
  697. string upperString = original.ToUpper();
  698. string upperPattern = pattern.ToUpper();
  699. int inc = (original.Length/pattern.Length) *
  700. (replacement.Length-pattern.Length);
  701. char [] chars = new char[original.Length + Math.Max(0, inc)];
  702. while( (position1 = upperString.IndexOf(upperPattern,
  703. position0)) != -1 )
  704. {
  705. for ( int i=position0 ; i < position1 ; ++i )
  706. chars[count++] = original[i];
  707. for ( int i=0 ; i < replacement.Length ; ++i )
  708. chars[count++] = replacement[i];
  709. position0 = position1+pattern.Length;
  710. }
  711. if ( position0 == 0 ) return original;
  712. for ( int i=position0 ; i < original.Length ; ++i )
  713. chars[count++] = original[i];
  714. return new string(chars, 0, count);
  715. }
  716. #endif
  717. /// <summary>
  718. /// Retrieve entries from the zipfile by specified criteria.
  719. /// </summary>
  720. ///
  721. /// <remarks>
  722. /// <para>
  723. /// This method allows callers to retrieve the collection of entries from the zipfile
  724. /// that fit the specified criteria. The criteria are described in a string format, and
  725. /// can include patterns for the filename; constraints on the size of the entry;
  726. /// constraints on the last modified, created, or last accessed time for the file
  727. /// described by the entry; or the attributes of the entry.
  728. /// </para>
  729. ///
  730. /// <para>
  731. /// For details on the syntax for the selectionCriteria parameter, see <see
  732. /// cref="AddSelectedFiles(String)"/>.
  733. /// </para>
  734. ///
  735. /// <para>
  736. /// This method is intended for use with a ZipFile that has been read from storage.
  737. /// When creating a new ZipFile, this method will work only after the ZipArchive has
  738. /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
  739. /// archive from storage.) Calling SelectEntries on a ZipFile that has not yet been
  740. /// saved will deliver undefined results.
  741. /// </para>
  742. /// </remarks>
  743. ///
  744. /// <exception cref="System.Exception">
  745. /// Thrown if selectionCriteria has an invalid syntax.
  746. /// </exception>
  747. ///
  748. /// <example>
  749. /// This example selects all the PhotoShop files from within an archive, and extracts them
  750. /// to the current working directory.
  751. /// <code>
  752. /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
  753. /// {
  754. /// var PhotoShopFiles = zip1.SelectEntries("*.psd");
  755. /// foreach (ZipEntry psd in PhotoShopFiles)
  756. /// {
  757. /// psd.Extract();
  758. /// }
  759. /// }
  760. /// </code>
  761. /// <code lang="VB">
  762. /// Using zip1 As ZipFile = ZipFile.Read(ZipFileName)
  763. /// Dim PhotoShopFiles as ICollection(Of ZipEntry)
  764. /// PhotoShopFiles = zip1.SelectEntries("*.psd")
  765. /// Dim psd As ZipEntry
  766. /// For Each psd In PhotoShopFiles
  767. /// psd.Extract
  768. /// Next
  769. /// End Using
  770. /// </code>
  771. /// </example>
  772. /// <param name="selectionCriteria">the string that specifies which entries to select</param>
  773. /// <returns>a collection of ZipEntry objects that conform to the inclusion spec</returns>
  774. public ICollection<ZipEntry> SelectEntries(String selectionCriteria)
  775. {
  776. Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
  777. AddDirectoryWillTraverseReparsePoints);
  778. return ff.SelectEntries(this);
  779. }
  780. /// <summary>
  781. /// Retrieve entries from the zipfile by specified criteria.
  782. /// </summary>
  783. ///
  784. /// <remarks>
  785. /// <para>
  786. /// This method allows callers to retrieve the collection of entries from the zipfile
  787. /// that fit the specified criteria. The criteria are described in a string format, and
  788. /// can include patterns for the filename; constraints on the size of the entry;
  789. /// constraints on the last modified, created, or last accessed time for the file
  790. /// described by the entry; or the attributes of the entry.
  791. /// </para>
  792. ///
  793. /// <para>
  794. /// For details on the syntax for the selectionCriteria parameter, see <see
  795. /// cref="AddSelectedFiles(String)"/>.
  796. /// </para>
  797. ///
  798. /// <para>
  799. /// This method is intended for use with a ZipFile that has been read from storage.
  800. /// When creating a new ZipFile, this method will work only after the ZipArchive has
  801. /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
  802. /// archive from storage.) Calling SelectEntries on a ZipFile that has not yet been
  803. /// saved will deliver undefined results.
  804. /// </para>
  805. /// </remarks>
  806. ///
  807. /// <exception cref="System.Exception">
  808. /// Thrown if selectionCriteria has an invalid syntax.
  809. /// </exception>
  810. ///
  811. /// <example>
  812. /// <code>
  813. /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
  814. /// {
  815. /// var UpdatedPhotoShopFiles = zip1.SelectEntries("*.psd", "UpdatedFiles");
  816. /// foreach (ZipEntry e in UpdatedPhotoShopFiles)
  817. /// {
  818. /// // prompt for extract here
  819. /// if (WantExtract(e.FileName))
  820. /// e.Extract();
  821. /// }
  822. /// }
  823. /// </code>
  824. /// <code lang="VB">
  825. /// Using zip1 As ZipFile = ZipFile.Read(ZipFileName)
  826. /// Dim UpdatedPhotoShopFiles As ICollection(Of ZipEntry) = zip1.SelectEntries("*.psd", "UpdatedFiles")
  827. /// Dim e As ZipEntry
  828. /// For Each e In UpdatedPhotoShopFiles
  829. /// ' prompt for extract here
  830. /// If Me.WantExtract(e.FileName) Then
  831. /// e.Extract
  832. /// End If
  833. /// Next
  834. /// End Using
  835. /// </code>
  836. /// </example>
  837. /// <param name="selectionCriteria">the string that specifies which entries to select</param>
  838. ///
  839. /// <param name="directoryPathInArchive">
  840. /// the directory in the archive from which to select entries. If null, then
  841. /// all directories in the archive are used.
  842. /// </param>
  843. ///
  844. /// <returns>a collection of ZipEntry objects that conform to the inclusion spec</returns>
  845. public ICollection<ZipEntry> SelectEntries(String selectionCriteria, string directoryPathInArchive)
  846. {
  847. Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
  848. AddDirectoryWillTraverseReparsePoints);
  849. return ff.SelectEntries(this, directoryPathInArchive);
  850. }
  851. /// <summary>
  852. /// Remove entries from the zipfile by specified criteria.
  853. /// </summary>
  854. ///
  855. /// <remarks>
  856. /// <para>
  857. /// This method allows callers to remove the collection of entries from the zipfile
  858. /// that fit the specified criteria. The criteria are described in a string format, and
  859. /// can include patterns for the filename; constraints on the size of the entry;
  860. /// constraints on the last modified, created, or last accessed time for the file
  861. /// described by the entry; or the attributes of the entry.
  862. /// </para>
  863. ///
  864. /// <para>
  865. /// For details on the syntax for the selectionCriteria parameter, see <see
  866. /// cref="AddSelectedFiles(String)"/>.
  867. /// </para>
  868. ///
  869. /// <para>
  870. /// This method is intended for use with a ZipFile that has been read from storage.
  871. /// When creating a new ZipFile, this method will work only after the ZipArchive has
  872. /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
  873. /// archive from storage.) Calling SelectEntries on a ZipFile that has not yet been
  874. /// saved will deliver undefined results.
  875. /// </para>
  876. /// </remarks>
  877. ///
  878. /// <exception cref="System.Exception">
  879. /// Thrown if selectionCriteria has an invalid syntax.
  880. /// </exception>
  881. ///
  882. /// <example>
  883. /// This example removes all entries in a zip file that were modified prior to January 1st, 2008.
  884. /// <code>
  885. /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
  886. /// {
  887. /// // remove all entries from prior to Jan 1, 2008
  888. /// zip1.RemoveEntries("mtime &lt; 2008-01-01");
  889. /// // don't forget to save the archive!
  890. /// zip1.Save();
  891. /// }
  892. /// </code>
  893. /// <code lang="VB">
  894. /// Using zip As ZipFile = ZipFile.Read(ZipFileName)
  895. /// ' remove all entries from prior to Jan 1, 2008
  896. /// zip1.RemoveEntries("mtime &lt; 2008-01-01")
  897. /// ' do not forget to save the archive!
  898. /// zip1.Save
  899. /// End Using
  900. /// </code>
  901. /// </example>
  902. /// <param name="selectionCriteria">the string that specifies which entries to select</param>
  903. /// <returns>the number of entries removed</returns>
  904. public int RemoveSelectedEntries(String selectionCriteria)
  905. {
  906. var selection = this.SelectEntries(selectionCriteria);
  907. this.RemoveEntries(selection);
  908. return selection.Count;
  909. }
  910. /// <summary>
  911. /// Remove entries from the zipfile by specified criteria, and within the specified
  912. /// path in the archive.
  913. /// </summary>
  914. ///
  915. /// <remarks>
  916. /// <para>
  917. /// This method allows callers to remove the collection of entries from the zipfile
  918. /// that fit the specified criteria. The criteria are described in a string format, and
  919. /// can include patterns for the filename; constraints on the size of the entry;
  920. /// constraints on the last modified, created, or last accessed time for the file
  921. /// described by the entry; or the attributes of the entry.
  922. /// </para>
  923. ///
  924. /// <para>
  925. /// For details on the syntax for the selectionCriteria parameter, see <see
  926. /// cref="AddSelectedFiles(String)"/>.
  927. /// </para>
  928. ///
  929. /// <para>
  930. /// This method is intended for use with a ZipFile that has been read from storage.
  931. /// When creating a new ZipFile, this method will work only after the ZipArchive has
  932. /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
  933. /// archive from storage.) Calling SelectEntries on a ZipFile that has not yet been
  934. /// saved will deliver undefined results.
  935. /// </para>
  936. /// </remarks>
  937. ///
  938. /// <exception cref="System.Exception">
  939. /// Thrown if selectionCriteria has an invalid syntax.
  940. /// </exception>
  941. ///
  942. /// <example>
  943. /// <code>
  944. /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
  945. /// {
  946. /// // remove all entries from prior to Jan 1, 2008
  947. /// zip1.RemoveEntries("mtime &lt; 2008-01-01", "documents");
  948. /// // a call to ZipFile.Save will make the modifications permanent
  949. /// zip1.Save();
  950. /// }
  951. /// </code>
  952. /// <code lang="VB">
  953. /// Using zip As ZipFile = ZipFile.Read(ZipFileName)
  954. /// ' remove all entries from prior to Jan 1, 2008
  955. /// zip1.RemoveEntries("mtime &lt; 2008-01-01", "documents")
  956. /// ' a call to ZipFile.Save will make the modifications permanent
  957. /// zip1.Save
  958. /// End Using
  959. /// </code>
  960. /// </example>
  961. ///
  962. /// <param name="selectionCriteria">the string that specifies which entries to select</param>
  963. /// <param name="directoryPathInArchive">
  964. /// the directory in the archive from which to select entries. If null, then
  965. /// all directories in the archive are used.
  966. /// </param>
  967. /// <returns>the number of entries removed</returns>
  968. public int RemoveSelectedEntries(String selectionCriteria, string directoryPathInArchive)
  969. {
  970. var selection = this.SelectEntries(selectionCriteria, directoryPathInArchive);
  971. this.RemoveEntries(selection);
  972. return selection.Count;
  973. }
  974. /// <summary>
  975. /// Selects and Extracts a set of Entries from the ZipFile.
  976. /// </summary>
  977. ///
  978. /// <remarks>
  979. /// <para>
  980. /// The entries are extracted into the current working directory.
  981. /// </para>
  982. ///
  983. /// <para>
  984. /// If any of the files to be extracted already exist, then the action taken is as
  985. /// specified in the <see cref="ZipEntry.ExtractExistingFile"/> property on the
  986. /// corresponding ZipEntry instance. By default, the action taken in this case is to
  987. /// throw an exception.
  988. /// </para>
  989. ///
  990. /// <para>
  991. /// For information on the syntax of the selectionCriteria string,
  992. /// see <see cref="AddSelectedFiles(String)" />.
  993. /// </para>
  994. /// </remarks>
  995. ///
  996. /// <example>
  997. /// This example shows how extract all XML files modified after 15 January 2009.
  998. /// <code>
  999. /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
  1000. /// {
  1001. /// zip.ExtractSelectedEntries("name = *.xml and mtime &gt; 2009-01-15");
  1002. /// }
  1003. /// </code>
  1004. /// </example>
  1005. /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
  1006. ///
  1007. /// <seealso cref="ExtractSelectedEntries(String,ExtractExistingFileAction)"/>
  1008. public void ExtractSelectedEntries(String selectionCriteria)
  1009. {
  1010. foreach (ZipEntry e in SelectEntries(selectionCriteria))
  1011. {
  1012. e.Password = _Password; // possibly null
  1013. e.Extract();
  1014. }
  1015. }
  1016. /// <summary>
  1017. /// Selects and Extracts a set of Entries from the ZipFile.
  1018. /// </summary>
  1019. ///
  1020. /// <remarks>
  1021. /// <para>
  1022. /// The entries are extracted into the current working directory. When extraction would would
  1023. /// overwrite an existing filesystem file, the action taken is as specified in the
  1024. /// <paramref name="extractExistingFile"/> parameter.
  1025. /// </para>
  1026. ///
  1027. /// <para>
  1028. /// For information on the syntax of the string describing the entry selection criteria,
  1029. /// see <see cref="AddSelectedFiles(String)" />.
  1030. /// </para>
  1031. /// </remarks>
  1032. ///
  1033. /// <example>
  1034. /// This example shows how extract all XML files modified after 15 January 2009,
  1035. /// overwriting any existing files.
  1036. /// <code>
  1037. /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
  1038. /// {
  1039. /// zip.ExtractSelectedEntries("name = *.xml and mtime &gt; 2009-01-15",
  1040. /// ExtractExistingFileAction.OverwriteSilently);
  1041. /// }
  1042. /// </code>
  1043. /// </example>
  1044. ///
  1045. /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
  1046. ///
  1047. /// <param name="extractExistingFile">
  1048. /// The action to take if extraction would overwrite an existing file.
  1049. /// </param>
  1050. public void ExtractSelectedEntries(String selectionCriteria, ExtractExistingFileAction extractExistingFile)
  1051. {
  1052. foreach (ZipEntry e in SelectEntries(selectionCriteria))
  1053. {
  1054. e.Password = _Password; // possibly null
  1055. e.Extract(extractExistingFile);
  1056. }
  1057. }
  1058. /// <summary>
  1059. /// Selects and Extracts a set of Entries from the ZipFile.
  1060. /// </summary>
  1061. ///
  1062. /// <remarks>
  1063. /// <para>
  1064. /// The entries are selected from the specified directory within the archive, and then
  1065. /// extracted into the current working directory.
  1066. /// </para>
  1067. ///
  1068. /// <para>
  1069. /// If any of the files to be extracted already exist, then the action taken is as
  1070. /// specified in the <see cref="ZipEntry.ExtractExistingFile"/> property on the
  1071. /// corresponding ZipEntry instance. By default, the action taken in this case is to
  1072. /// throw an exception.
  1073. /// </para>
  1074. ///
  1075. /// <para>
  1076. /// For information on the syntax of the string describing the entry selection criteria,
  1077. /// see <see cref="AddSelectedFiles(String)" />.
  1078. /// </para>
  1079. /// </remarks>
  1080. ///
  1081. /// <example>
  1082. /// This example shows how extract all XML files modified after 15 January 2009,
  1083. /// and writes them to the "unpack" directory.
  1084. /// <code>
  1085. /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
  1086. /// {
  1087. /// zip.ExtractSelectedEntries("name = *.xml and mtime &gt; 2009-01-15","unpack");
  1088. /// }
  1089. /// </code>
  1090. /// </example>
  1091. ///
  1092. /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
  1093. ///
  1094. /// <param name="directoryPathInArchive">
  1095. /// the directory in the archive from which to select entries. If null, then
  1096. /// all directories in the archive are used.
  1097. /// </param>
  1098. ///
  1099. /// <seealso cref="ExtractSelectedEntries(String,String,String,ExtractExistingFileAction)"/>
  1100. public void ExtractSelectedEntries(String selectionCriteria, String directoryPathInArchive)
  1101. {
  1102. foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryPathInArchive))
  1103. {
  1104. e.Password = _Password; // possibly null
  1105. e.Extract();
  1106. }
  1107. }
  1108. /// <summary>
  1109. /// Selects and Extracts a set of Entries from the ZipFile.
  1110. /// </summary>
  1111. ///
  1112. /// <remarks>
  1113. /// <para>
  1114. /// The entries are extracted into the specified directory. If any of the files to be
  1115. /// extracted already exist, an exception will be thrown.
  1116. /// </para>
  1117. /// <para>
  1118. /// For information on the syntax of the string describing the entry selection criteria,
  1119. /// see <see cref="AddSelectedFiles(String)" />.
  1120. /// </para>
  1121. /// </remarks>
  1122. ///
  1123. /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
  1124. ///
  1125. /// <param name="directoryInArchive">
  1126. /// the directory in the archive from which to select entries. If null, then
  1127. /// all directories in the archive are used.
  1128. /// </param>
  1129. ///
  1130. /// <param name="extractDirectory">
  1131. /// the directory on the disk into which to extract. It will be created
  1132. /// if it does not exist.
  1133. /// </param>
  1134. public void ExtractSelectedEntries(String selectionCriteria, string directoryInArchive, string extractDirectory)
  1135. {
  1136. foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryInArchive))
  1137. {
  1138. e.Password = _Password; // possibly null
  1139. e.Extract(extractDirectory);
  1140. }
  1141. }
  1142. /// <summary>
  1143. /// Selects and Extracts a set of Entries from the ZipFile.
  1144. /// </summary>
  1145. ///
  1146. /// <remarks>
  1147. /// <para>
  1148. /// The entries are extracted into the specified directory. When extraction would would
  1149. /// overwrite an existing filesystem file, the action taken is as specified in the
  1150. /// <paramref name="extractExistingFile"/> parameter.
  1151. /// </para>
  1152. ///
  1153. /// <para>
  1154. /// For information on the syntax of the string describing the entry selection criteria,
  1155. /// see <see cref="AddSelectedFiles(String)" />.
  1156. /// </para>
  1157. /// </remarks>
  1158. ///
  1159. /// <example>
  1160. /// This example shows how extract all files with an XML extension or with a size larger than 100,000 bytes,
  1161. /// and puts them in the unpack directory. For any files that already exist in
  1162. /// that destination directory, they will not be overwritten.
  1163. /// <code>
  1164. /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
  1165. /// {
  1166. /// zip.ExtractSelectedEntries("name = *.xml or size &gt; 100000",
  1167. /// null,
  1168. /// "unpack",
  1169. /// ExtractExistingFileAction.DontOverwrite);
  1170. /// }
  1171. /// </code>
  1172. /// </example>
  1173. ///
  1174. /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
  1175. ///
  1176. /// <param name="extractDirectory">
  1177. /// The directory on the disk into which to extract. It will be created if it does not exist.
  1178. /// </param>
  1179. ///
  1180. /// <param name="directoryPathInArchive">
  1181. /// The directory in the archive from which to select entries. If null, then
  1182. /// all directories in the archive are used.
  1183. /// </param>
  1184. ///
  1185. /// <param name="extractExistingFile">
  1186. /// The action to take if extraction would overwrite an existing file.
  1187. /// </param>
  1188. ///
  1189. public void ExtractSelectedEntries(String selectionCriteria, string directoryPathInArchive, string extractDirectory, ExtractExistingFileAction extractExistingFile)
  1190. {
  1191. foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryPathInArchive))
  1192. {
  1193. e.Password = _Password; // possibly null
  1194. e.Extract(extractDirectory, extractExistingFile);
  1195. }
  1196. }
  1197. }
  1198. }
  1199. namespace Ionic
  1200. {
  1201. internal abstract partial class SelectionCriterion
  1202. {
  1203. internal abstract bool Evaluate(Ionic.Zip.ZipEntry entry);
  1204. }
  1205. internal partial class NameCriterion : SelectionCriterion
  1206. {
  1207. internal override bool Evaluate(Ionic.Zip.ZipEntry entry)
  1208. {
  1209. // swap slashes in reference to local configuration
  1210. string transformedFileName = entry.FileName.Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar);
  1211. return _Evaluate(transformedFileName);
  1212. }
  1213. }
  1214. internal partial class SizeCriterion : SelectionCriterion
  1215. {
  1216. internal override bool Evaluate(Ionic.Zip.ZipEntry entry)
  1217. {
  1218. return _Evaluate(entry.UncompressedSize);
  1219. }
  1220. }
  1221. internal partial class TimeCriterion : SelectionCriterion
  1222. {
  1223. internal override bool Evaluate(Ionic.Zip.ZipEntry entry)
  1224. {
  1225. DateTime x;
  1226. switch (Which)
  1227. {
  1228. case WhichTime.atime:
  1229. x = entry.AccessedTime;
  1230. break;
  1231. case WhichTime.mtime:
  1232. x = entry.ModifiedTime;
  1233. break;
  1234. case WhichTime.ctime:
  1235. x = entry.CreationTime;
  1236. break;
  1237. default: throw new ArgumentException("??time");
  1238. }
  1239. return _Evaluate(x);
  1240. }
  1241. }
  1242. internal partial class TypeCriterion : SelectionCriterion
  1243. {
  1244. internal override bool Evaluate(Ionic.Zip.ZipEntry entry)
  1245. {
  1246. bool result = (ObjectType == 'D')
  1247. ? entry.IsDirectory
  1248. : !entry.IsDirectory;
  1249. if (Operator != ComparisonOperator.EqualTo)
  1250. result = !result;
  1251. return result;
  1252. }
  1253. }
  1254. #if !SILVERLIGHT
  1255. internal partial class AttributesCriterion : SelectionCriterion
  1256. {
  1257. internal override bool Evaluate(Ionic.Zip.ZipEntry entry)
  1258. {
  1259. FileAttributes fileAttrs = entry.Attributes;
  1260. return _Evaluate(fileAttrs);
  1261. }
  1262. }
  1263. #endif
  1264. internal partial class CompoundCriterion : SelectionCriterion
  1265. {
  1266. internal override bool Evaluate(Ionic.Zip.ZipEntry entry)
  1267. {
  1268. bool result = Left.Evaluate(entry);
  1269. switch (Conjunction)
  1270. {
  1271. case LogicalConjunction.AND:
  1272. if (result)
  1273. result = Right.Evaluate(entry);
  1274. break;
  1275. case LogicalConjunction.OR:
  1276. if (!result)
  1277. result = Right.Evaluate(entry);
  1278. break;
  1279. case LogicalConjunction.XOR:
  1280. result ^= Right.Evaluate(entry);
  1281. break;
  1282. }
  1283. return result;
  1284. }
  1285. }
  1286. public partial class FileSelector
  1287. {
  1288. private bool Evaluate(Ionic.Zip.ZipEntry entry)
  1289. {
  1290. bool result = _Criterion.Evaluate(entry);
  1291. return result;
  1292. }
  1293. /// <summary>
  1294. /// Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria.
  1295. /// </summary>
  1296. /// <remarks>
  1297. ///
  1298. /// <para>
  1299. /// This method applies the criteria set in the FileSelector instance (as described in
  1300. /// the <see cref="FileSelector.SelectionCriteria"/>) to the specified ZipFile. Using this
  1301. /// method, for example, you can retrieve all entries from the given ZipFile that
  1302. /// have filenames ending in .txt.
  1303. /// </para>
  1304. ///
  1305. /// <para>
  1306. /// Normally, applications would not call this method directly. This method is used
  1307. /// by the ZipFile class.
  1308. /// </para>
  1309. ///
  1310. /// <para>
  1311. /// Using the appropriate SelectionCriteria, you can retrieve entries based on size,
  1312. /// time, and attributes. See <see cref="FileSelector.SelectionCriteria"/> for a
  1313. /// description of the syntax of the SelectionCriteria string.
  1314. /// </para>
  1315. ///
  1316. /// </remarks>
  1317. ///
  1318. /// <param name="zip">The ZipFile from which to retrieve entries.</param>
  1319. ///
  1320. /// <returns>a collection of ZipEntry objects that conform to the criteria.</returns>
  1321. public ICollection<Ionic.Zip.ZipEntry> SelectEntries(Ionic.Zip.ZipFile zip)
  1322. {
  1323. if (zip == null)
  1324. throw new ArgumentNullException("zip");
  1325. var list = new List<Ionic.Zip.ZipEntry>();
  1326. foreach (Ionic.Zip.ZipEntry e in zip)
  1327. {
  1328. if (this.Evaluate(e))
  1329. list.Add(e);
  1330. }
  1331. return list;
  1332. }
  1333. /// <summary>
  1334. /// Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria.
  1335. /// </summary>
  1336. /// <remarks>
  1337. ///
  1338. /// <para>
  1339. /// This method applies the criteria set in the FileSelector instance (as described in
  1340. /// the <see cref="FileSelector.SelectionCriteria"/>) to the specified ZipFile. Using this
  1341. /// method, for example, you can retrieve all entries from the given ZipFile that
  1342. /// have filenames ending in .txt.
  1343. /// </para>
  1344. ///
  1345. /// <para>
  1346. /// Normally, applications would not call this method directly. This method is used
  1347. /// by the ZipFile class.
  1348. /// </para>
  1349. ///
  1350. /// <para>
  1351. /// This overload allows the selection of ZipEntry instances from the ZipFile to be restricted
  1352. /// to entries contained within a particular directory in the ZipFile.
  1353. /// </para>
  1354. ///
  1355. /// <para>
  1356. /// Using the appropriate SelectionCriteria, you can retrieve entries based on size,
  1357. /// time, and attributes. See <see cref="FileSelector.SelectionCriteria"/> for a
  1358. /// description of the syntax of the SelectionCriteria string.
  1359. /// </para>
  1360. ///
  1361. /// </remarks>
  1362. ///
  1363. /// <param name="zip">The ZipFile from which to retrieve entries.</param>
  1364. ///
  1365. /// <param name="directoryPathInArchive">
  1366. /// the directory in the archive from which to select entries. If null, then
  1367. /// all directories in the archive are used.
  1368. /// </param>
  1369. ///
  1370. /// <returns>a collection of ZipEntry objects that conform to the criteria.</returns>
  1371. public ICollection<Ionic.Zip.ZipEntry> SelectEntries(Ionic.Zip.ZipFile zip, string directoryPathInArchive)
  1372. {
  1373. if (zip == null)
  1374. throw new ArgumentNullException("zip");
  1375. var list = new List<Ionic.Zip.ZipEntry>();
  1376. // workitem 8559
  1377. string slashSwapped = (directoryPathInArchive == null) ? null : directoryPathInArchive.Replace("/", "\\");
  1378. // workitem 9174
  1379. if (slashSwapped != null)
  1380. {
  1381. while (slashSwapped.EndsWith("\\"))
  1382. slashSwapped = slashSwapped.Substring(0, slashSwapped.Length - 1);
  1383. }
  1384. foreach (Ionic.Zip.ZipEntry e in zip)
  1385. {
  1386. if (directoryPathInArchive == null || (Path.GetDirectoryName(e.FileName) == directoryPathInArchive)
  1387. || (Path.GetDirectoryName(e.FileName) == slashSwapped)) // workitem 8559
  1388. if (this.Evaluate(e))
  1389. list.Add(e);
  1390. }
  1391. return list;
  1392. }
  1393. }
  1394. }