1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.types;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.util.Arrays;
  21. import java.util.Vector;
  22. import java.util.Hashtable;
  23. import java.util.Enumeration;
  24. import java.util.zip.ZipException;
  25. import org.apache.tools.ant.BuildException;
  26. import org.apache.tools.ant.DirectoryScanner;
  27. import org.apache.tools.zip.ZipEntry;
  28. import org.apache.tools.zip.ZipFile;
  29. /**
  30. * ZipScanner accesses the pattern matching algorithm in DirectoryScanner,
  31. * which are protected methods that can only be accessed by subclassing.
  32. *
  33. * This implementation of FileScanner defines getIncludedFiles to return
  34. * the matching Zip entries.
  35. *
  36. */
  37. public class ZipScanner extends DirectoryScanner {
  38. /**
  39. * The zip file which should be scanned.
  40. */
  41. protected File srcFile;
  42. /**
  43. * to record the last scanned zip file with its modification date
  44. */
  45. private Resource lastScannedResource;
  46. /**
  47. * record list of all zip entries
  48. */
  49. private Hashtable myentries;
  50. /**
  51. * encoding of file names.
  52. *
  53. * @since Ant 1.6
  54. */
  55. private String encoding;
  56. /**
  57. * Sets the srcFile for scanning. This is the jar or zip file that
  58. * is scanned for matching entries.
  59. *
  60. * @param srcFile the (non-null) zip file name for scanning
  61. */
  62. public void setSrc(File srcFile) {
  63. this.srcFile = srcFile;
  64. }
  65. /**
  66. * Sets encoding of file names.
  67. *
  68. * @since Ant 1.6
  69. */
  70. public void setEncoding(String encoding) {
  71. this.encoding = encoding;
  72. }
  73. /**
  74. * Returns the names of the files which matched at least one of the
  75. * include patterns and none of the exclude patterns.
  76. * The names are relative to the base directory.
  77. *
  78. * @return the names of the files which matched at least one of the
  79. * include patterns and none of the exclude patterns.
  80. */
  81. public String[] getIncludedFiles() {
  82. if (srcFile != null) {
  83. Vector myvector = new Vector();
  84. // first check if the archive needs to be scanned again
  85. scanme();
  86. for (Enumeration e = myentries.elements(); e.hasMoreElements();) {
  87. Resource myresource = (Resource) e.nextElement();
  88. if (!myresource.isDirectory() && match(myresource.getName())) {
  89. myvector.addElement(myresource.getName());
  90. }
  91. }
  92. String[] files = new String[myvector.size()];
  93. myvector.copyInto(files);
  94. Arrays.sort(files);
  95. return files;
  96. } else {
  97. return super.getIncludedFiles();
  98. }
  99. }
  100. /**
  101. * Returns the names of the directories which matched at least one of the
  102. * include patterns and none of the exclude patterns.
  103. * The names are relative to the base directory.
  104. *
  105. * @return the names of the directories which matched at least one of the
  106. * include patterns and none of the exclude patterns.
  107. */
  108. public String[] getIncludedDirectories() {
  109. if (srcFile != null) {
  110. Vector myvector = new Vector();
  111. // first check if the archive needs to be scanned again
  112. scanme();
  113. for (Enumeration e = myentries.elements(); e.hasMoreElements();) {
  114. Resource myresource = (Resource) e.nextElement();
  115. if (myresource.isDirectory() && match(myresource.getName())) {
  116. myvector.addElement(myresource.getName());
  117. }
  118. }
  119. String[] files = new String[myvector.size()];
  120. myvector.copyInto(files);
  121. Arrays.sort(files);
  122. return files;
  123. } else {
  124. return super.getIncludedDirectories();
  125. }
  126. }
  127. /**
  128. * Initialize DirectoryScanner data structures.
  129. */
  130. public void init() {
  131. if (includes == null) {
  132. // No includes supplied, so set it to 'matches all'
  133. includes = new String[1];
  134. includes[0] = "**";
  135. }
  136. if (excludes == null) {
  137. excludes = new String[0];
  138. }
  139. }
  140. /**
  141. * Matches a jar entry against the includes/excludes list,
  142. * normalizing the path separator.
  143. *
  144. * @param path the (non-null) path name to test for inclusion
  145. *
  146. * @return <code>true</code> if the path should be included
  147. * <code>false</code> otherwise.
  148. */
  149. public boolean match(String path) {
  150. String vpath = path.replace('/', File.separatorChar).
  151. replace('\\', File.separatorChar);
  152. return isIncluded(vpath) && !isExcluded(vpath);
  153. }
  154. /**
  155. * @param name path name of the file sought in the archive
  156. *
  157. * @since Ant 1.5.2
  158. */
  159. public Resource getResource(String name) {
  160. if (srcFile == null) {
  161. return super.getResource(name);
  162. } else if (name.equals("")) {
  163. // special case in ZIPs, we do not want this thing included
  164. return new Resource("", true, Long.MAX_VALUE, true);
  165. }
  166. // first check if the archive needs to be scanned again
  167. scanme();
  168. if (myentries.containsKey(name)) {
  169. return (Resource) myentries.get(name);
  170. } else if (myentries.containsKey(name + "/")) {
  171. return (Resource) myentries.get(name + "/");
  172. } else {
  173. return new Resource(name);
  174. }
  175. }
  176. /**
  177. * if the datetime of the archive did not change since
  178. * lastScannedResource was initialized returns immediately else if
  179. * the archive has not been scanned yet, then all the zip entries
  180. * are put into the vector myentries as a vector of the resource
  181. * type
  182. */
  183. private void scanme() {
  184. Resource thisresource = new Resource(srcFile.getAbsolutePath(),
  185. srcFile.exists(),
  186. srcFile.lastModified());
  187. // spare scanning again and again
  188. if (lastScannedResource != null
  189. && lastScannedResource.getName().equals(thisresource.getName())
  190. && lastScannedResource.getLastModified()
  191. == thisresource.getLastModified()) {
  192. return;
  193. }
  194. ZipEntry entry = null;
  195. ZipFile zf = null;
  196. myentries = new Hashtable();
  197. try {
  198. try {
  199. zf = new ZipFile(srcFile, encoding);
  200. } catch (ZipException ex) {
  201. throw new BuildException("problem reading " + srcFile, ex);
  202. } catch (IOException ex) {
  203. throw new BuildException("problem opening " + srcFile, ex);
  204. }
  205. Enumeration e = zf.getEntries();
  206. while (e.hasMoreElements()) {
  207. entry = (ZipEntry) e.nextElement();
  208. myentries.put(new String(entry.getName()),
  209. new Resource(entry.getName(), true,
  210. entry.getTime(),
  211. entry.isDirectory()));
  212. }
  213. } finally {
  214. if (zf != null) {
  215. try {
  216. zf.close();
  217. } catch (IOException ex) {
  218. // swallow
  219. }
  220. }
  221. }
  222. // record data about the last scanned resource
  223. lastScannedResource = thisresource;
  224. }
  225. }