View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2.filter;
18  
19  import java.io.File;
20  import java.util.Objects;
21  
22  /**
23   * Enumeration of IO case sensitivity.
24   * <p>
25   * Different filing systems have different rules for case-sensitivity. Windows
26   * is case-insensitive, Unix is case-sensitive.
27   * </p>
28   * <p>
29   * This class captures that difference, providing an enumeration to control how
30   * file name comparisons should be performed. It also provides methods that use
31   * the enumeration to perform comparisons.
32   * </p>
33   * <p>
34   * Wherever possible, you should use the {@code check} methods in this
35   * class to compare file names.
36   * </p>
37   *
38   * @author This code was originally ported from Apache Commons IO File Filter
39   * @see "https://commons.apache.org/proper/commons-io/"
40   * @since 2.4
41   */
42  public enum IOCase {
43  
44      /**
45       * The constant for case-sensitive regardless of operating system.
46       */
47      SENSITIVE("Sensitive", true),
48  
49      /**
50       * The constant for case-insensitive regardless of operating system.
51       */
52      INSENSITIVE("Insensitive", false),
53  
54      /**
55       * The constant for case sensitivity determined by the current operating system.
56       * Windows is case-insensitive when comparing file names, Unix is case-sensitive.
57       * <p>
58       * <strong>Note:</strong> This only caters for Windows and Unix. Other operating
59       * systems (e.g. OSX and OpenVMS) are treated as case-sensitive if they use the
60       * Unix file separator and case-insensitive if they use the Windows file
61       * separator (see {@link File#separatorChar}).
62       * <p>
63       * If you serialize this constant on Windows, and deserialize on Unix, or vice
64       * versa, then the value of the case-sensitivity flag will change.
65       */
66      SYSTEM("System", !(File.separatorChar == '\\'));
67  
68      /** Serialization version. */
69      private static final long serialVersionUID = -6343169151696340687L;
70  
71      /**
72       * Factory method to create an IOCase from a name.
73       *
74       * @param name the name to find
75       * @return the IOCase object
76       * @throws IllegalArgumentException if the name is invalid
77       */
78      public static IOCase forName(final String name) {
79          for (final IOCase ioCase : values()) {
80              if (ioCase.getName().equals(name)) {
81                  return ioCase;
82              }
83          }
84          throw new IllegalArgumentException("Invalid IOCase name: " + name);
85      }
86  
87      /** The enumeration name. */
88      private final String name;
89  
90      /** The sensitivity flag. */
91      private final transient boolean sensitive;
92  
93      /**
94       * Constructs a new instance.
95       *
96       * @param name      the name
97       * @param sensitive the sensitivity
98       */
99      IOCase(final String name, final boolean sensitive) {
100         this.name = name;
101         this.sensitive = sensitive;
102     }
103 
104     /**
105      * Compares two strings using the case-sensitivity rule.
106      * <p>
107      * This method mimics {@link String#compareTo} but takes case-sensitivity into
108      * account.
109      *
110      * @param str1 the first string to compare, not null
111      * @param str2 the second string to compare, not null
112      * @return true if equal using the case rules
113      * @throws NullPointerException if either string is null
114      */
115     public int checkCompareTo(final String str1, final String str2) {
116         Objects.requireNonNull(str1, "str1");
117         Objects.requireNonNull(str2, "str2");
118         return sensitive ? str1.compareTo(str2) : str1.compareToIgnoreCase(str2);
119     }
120 
121     /**
122      * Checks if one string ends with another using the case-sensitivity rule.
123      * <p>
124      * This method mimics {@link String#endsWith} but takes case-sensitivity into
125      * account.
126      *
127      * @param str the string to check, not null
128      * @param end the end to compare against, not null
129      * @return true if equal using the case rules
130      * @throws NullPointerException if either string is null
131      */
132     public boolean checkEndsWith(final String str, final String end) {
133         final int endLen = end.length();
134         return str.regionMatches(!sensitive, str.length() - endLen, end, 0, endLen);
135     }
136 
137     /**
138      * Compares two strings using the case-sensitivity rule.
139      * <p>
140      * This method mimics {@link String#equals} but takes case-sensitivity into
141      * account.
142      *
143      * @param str1 the first string to compare, not null
144      * @param str2 the second string to compare, not null
145      * @return true if equal using the case rules
146      * @throws NullPointerException if either string is null
147      */
148     public boolean checkEquals(final String str1, final String str2) {
149         if (str1 == null || str2 == null) {
150             throw new NullPointerException("The strings must not be null");
151         }
152         return sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2);
153     }
154 
155     /**
156      * Checks if one string contains another starting at a specific index using the
157      * case-sensitivity rule.
158      * <p>
159      * This method mimics parts of {@link String#indexOf(String, int)} but takes
160      * case-sensitivity into account.
161      *
162      * @param str           the string to check, not null
163      * @param strStartIndex the index to start at in str
164      * @param search        the start to search for, not null
165      * @return the first index of the search String, -1 if no match or {@code null}
166      *         string input
167      * @throws NullPointerException if either string is null
168      * @since 2.0
169      */
170     public int checkIndexOf(final String str, final int strStartIndex, final String search) {
171         final int endIndex = str.length() - search.length();
172         if (endIndex >= strStartIndex) {
173             for (int i = strStartIndex; i <= endIndex; i++) {
174                 if (checkRegionMatches(str, i, search)) {
175                     return i;
176                 }
177             }
178         }
179         return -1;
180     }
181 
182     /**
183      * Checks if one string contains another at a specific index using the
184      * case-sensitivity rule.
185      * <p>
186      * This method mimics parts of
187      * {@link String#regionMatches(boolean, int, String, int, int)} but takes
188      * case-sensitivity into account.
189      *
190      * @param str           the string to check, not null
191      * @param strStartIndex the index to start at in str
192      * @param search        the start to search for, not null
193      * @return true if equal using the case rules
194      * @throws NullPointerException if either string is null
195      */
196     public boolean checkRegionMatches(final String str, final int strStartIndex, final String search) {
197         return str.regionMatches(!sensitive, strStartIndex, search, 0, search.length());
198     }
199 
200     /**
201      * Checks if one string starts with another using the case-sensitivity rule.
202      * <p>
203      * This method mimics {@link String#startsWith(String)} but takes
204      * case-sensitivity into account.
205      *
206      * @param str   the string to check, not null
207      * @param start the start to compare against, not null
208      * @return true if equal using the case rules
209      * @throws NullPointerException if either string is null
210      */
211     public boolean checkStartsWith(final String str, final String start) {
212         return str.regionMatches(!sensitive, 0, start, 0, start.length());
213     }
214 
215     /**
216      * Gets the name of the constant.
217      *
218      * @return the name of the constant
219      */
220     public String getName() {
221         return name;
222     }
223 
224     /**
225      * Does the object represent case-sensitive comparison.
226      *
227      * @return true if case-sensitive
228      */
229     public boolean isCaseSensitive() {
230         return sensitive;
231     }
232 
233     /**
234      * Replaces the enumeration from the stream with a real one. This ensures that
235      * the correct flag is set for SYSTEM.
236      *
237      * @return the resolved object
238      */
239     private Object readResolve() {
240         return forName(name);
241     }
242 
243     /**
244      * Gets a string describing the sensitivity.
245      *
246      * @return a string describing the sensitivity
247      */
248     @Override
249     public String toString() {
250         return name;
251     }
252 
253 }