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 }