1. /*
  2. * Copyright 2002-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.selectors;
  18. import java.io.File;
  19. import org.apache.tools.ant.types.EnumeratedAttribute;
  20. import org.apache.tools.ant.types.Parameter;
  21. /**
  22. * Selector that filters files based on their size.
  23. *
  24. * @since 1.5
  25. */
  26. public class SizeSelector extends BaseExtendSelector {
  27. private long size = -1;
  28. private long multiplier = 1;
  29. private long sizelimit = -1;
  30. private int cmp = 2;
  31. /** Used for parameterized custom selector */
  32. public static final String SIZE_KEY = "value";
  33. /** Used for parameterized custom selector */
  34. public static final String UNITS_KEY = "units";
  35. /** Used for parameterized custom selector */
  36. public static final String WHEN_KEY = "when";
  37. /**
  38. * Creates a new <code>SizeSelector</code> instance.
  39. *
  40. */
  41. public SizeSelector() {
  42. }
  43. /**
  44. * @return a string describing this object
  45. */
  46. public String toString() {
  47. StringBuffer buf = new StringBuffer("{sizeselector value: ");
  48. buf.append(sizelimit);
  49. buf.append("compare: ");
  50. if (cmp == 0) {
  51. buf.append("less");
  52. } else if (cmp == 1) {
  53. buf.append("more");
  54. } else {
  55. buf.append("equal");
  56. }
  57. buf.append("}");
  58. return buf.toString();
  59. }
  60. /**
  61. * A size selector needs to know what size to base its selecting on.
  62. * This will be further modified by the multiplier to get an
  63. * actual size limit.
  64. *
  65. * @param size the size to select against expressed in units
  66. */
  67. public void setValue(long size) {
  68. this.size = size;
  69. if ((multiplier != 0) && (size > -1)) {
  70. sizelimit = size * multiplier;
  71. }
  72. }
  73. /**
  74. * Sets the units to use for the comparison. This is a little
  75. * complicated because common usage has created standards that
  76. * play havoc with capitalization rules. Thus, some people will
  77. * use "K" for indicating 1000's, when the SI standard calls for
  78. * "k". Others have tried to introduce "K" as a multiple of 1024,
  79. * but that falls down when you reach "M", since "m" is already
  80. * defined as 0.001.
  81. * <p>
  82. * To get around this complexity, a number of standards bodies
  83. * have proposed the 2^10 standard, and at least one has adopted
  84. * it. But we are still left with a populace that isn't clear on
  85. * how capitalization should work.
  86. * <p>
  87. * We therefore ignore capitalization as much as possible.
  88. * Completely mixed case is not possible, but all upper and lower
  89. * forms are accepted for all long and short forms. Since we have
  90. * no need to work with the 0.001 case, this practice works here.
  91. * <p>
  92. * This function translates all the long and short forms that a
  93. * unit prefix can occur in and translates them into a single
  94. * multiplier.
  95. *
  96. * @param units The units to compare the size to, using an
  97. * EnumeratedAttribute
  98. */
  99. public void setUnits(ByteUnits units) {
  100. int i = units.getIndex();
  101. multiplier = 0;
  102. if ((i > -1) && (i < 4)) {
  103. multiplier = 1000;
  104. } else if ((i > 3) && (i < 9)) {
  105. multiplier = 1024;
  106. } else if ((i > 8) && (i < 13)) {
  107. multiplier = 1000000;
  108. } else if ((i > 12) && (i < 18)) {
  109. multiplier = 1048576;
  110. } else if ((i > 17) && (i < 22)) {
  111. multiplier = 1000000000L;
  112. } else if ((i > 21) && (i < 27)) {
  113. multiplier = 1073741824L;
  114. } else if ((i > 26) && (i < 31)) {
  115. multiplier = 1000000000000L;
  116. } else if ((i > 30) && (i < 36)) {
  117. multiplier = 1099511627776L;
  118. }
  119. if ((multiplier > 0) && (size > -1)) {
  120. sizelimit = size * multiplier;
  121. }
  122. }
  123. /**
  124. * This specifies when the file should be selected, whether it be
  125. * when the file matches a particular size, when it is smaller,
  126. * or whether it is larger.
  127. *
  128. * @param cmp The comparison to perform, an EnumeratedAttribute
  129. */
  130. public void setWhen(SizeComparisons cmp) {
  131. this.cmp = cmp.getIndex();
  132. }
  133. /**
  134. * When using this as a custom selector, this method will be called.
  135. * It translates each parameter into the appropriate setXXX() call.
  136. *
  137. * @param parameters the complete set of parameters for this selector
  138. */
  139. public void setParameters(Parameter[] parameters) {
  140. super.setParameters(parameters);
  141. if (parameters != null) {
  142. for (int i = 0; i < parameters.length; i++) {
  143. String paramname = parameters[i].getName();
  144. if (SIZE_KEY.equalsIgnoreCase(paramname)) {
  145. try {
  146. setValue(new Long(parameters[i].getValue()
  147. ).longValue());
  148. } catch (NumberFormatException nfe) {
  149. setError("Invalid size setting "
  150. + parameters[i].getValue());
  151. }
  152. } else if (UNITS_KEY.equalsIgnoreCase(paramname)) {
  153. ByteUnits units = new ByteUnits();
  154. units.setValue(parameters[i].getValue());
  155. setUnits(units);
  156. } else if (WHEN_KEY.equalsIgnoreCase(paramname)) {
  157. SizeComparisons cmp = new SizeComparisons();
  158. cmp.setValue(parameters[i].getValue());
  159. setWhen(cmp);
  160. } else {
  161. setError("Invalid parameter " + paramname);
  162. }
  163. }
  164. }
  165. }
  166. /**
  167. * <p>Checks to make sure all settings are kosher. In this case, it
  168. * means that the size attribute has been set (to a positive value),
  169. * that the multiplier has a valid setting, and that the size limit
  170. * is valid. Since the latter is a calculated value, this can only
  171. * fail due to a programming error.
  172. * </p>
  173. * <p>If a problem is detected, the setError() method is called.
  174. * </p>
  175. */
  176. public void verifySettings() {
  177. if (size < 0) {
  178. setError("The value attribute is required, and must be positive");
  179. } else if (multiplier < 1) {
  180. setError("Invalid Units supplied, must be K,Ki,M,Mi,G,Gi,T,or Ti");
  181. } else if (sizelimit < 0) {
  182. setError("Internal error: Code is not setting sizelimit correctly");
  183. }
  184. }
  185. /**
  186. * The heart of the matter. This is where the selector gets to decide
  187. * on the inclusion of a file in a particular fileset.
  188. *
  189. * @param basedir A java.io.File object for the base directory
  190. * @param filename The name of the file to check
  191. * @param file A File object for this filename
  192. * @return whether the file should be selected or not
  193. */
  194. public boolean isSelected(File basedir, String filename, File file) {
  195. // throw BuildException on error
  196. validate();
  197. // Directory size never selected for
  198. if (file.isDirectory()) {
  199. return true;
  200. }
  201. if (cmp == 0) {
  202. return (file.length() < sizelimit);
  203. } else if (cmp == 1) {
  204. return (file.length() > sizelimit);
  205. } else {
  206. return (file.length() == sizelimit);
  207. }
  208. }
  209. /**
  210. * Enumerated attribute with the values for units.
  211. * <p>
  212. * This treats the standard SI units as representing powers of ten,
  213. * as they should. If you want the powers of 2 that approximate
  214. * the SI units, use the first two characters followed by a
  215. * <code>bi</code>. So 1024 (2^10) becomes <code>kibi</code>,
  216. * 1048576 (2^20) becomes <code>mebi</code>, 1073741824 (2^30)
  217. * becomes <code>gibi</code>, and so on. The symbols are also
  218. * accepted, and these are the first letter capitalized followed
  219. * by an <code>i</code>. <code>Ki</code>, <code>Mi</code>,
  220. * <code>Gi</code>, and so on. Capitalization variations on these
  221. * are also accepted.
  222. * <p>
  223. * This binary prefix system is approved by the IEC and appears on
  224. * its way for approval by other agencies, but it is not an SI
  225. * standard. It disambiguates things for us, though.
  226. */
  227. public static class ByteUnits extends EnumeratedAttribute {
  228. /**
  229. * @return the values as an array of strings
  230. */
  231. public String[] getValues() {
  232. return new String[]{"K", "k", "kilo", "KILO",
  233. "Ki", "KI", "ki", "kibi", "KIBI",
  234. "M", "m", "mega", "MEGA",
  235. "Mi", "MI", "mi", "mebi", "MEBI",
  236. "G", "g", "giga", "GIGA",
  237. "Gi", "GI", "gi", "gibi", "GIBI",
  238. "T", "t", "tera", "TERA",
  239. /* You wish! */ "Ti", "TI", "ti", "tebi", "TEBI"
  240. };
  241. }
  242. }
  243. /**
  244. * Enumerated attribute with the values for size comparison.
  245. */
  246. public static class SizeComparisons extends EnumeratedAttribute {
  247. /**
  248. * @return the values as an array of strings
  249. */
  250. public String[] getValues() {
  251. return new String[]{"less", "more", "equal"};
  252. }
  253. }
  254. }