001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.io;
018
019 import java.io.Serializable;
020
021 /**
022 * Enumeration of IO case sensitivity.
023 * <p>
024 * Different filing systems have different rules for case-sensitivity.
025 * Windows is case-insensitive, Unix is case-sensitive.
026 * <p>
027 * This class captures that difference, providing an enumeration to
028 * control how filename comparisons should be performed. It also provides
029 * methods that use the enumeration to perform comparisons.
030 * <p>
031 * Wherever possible, you should use the <code>check</code> methods in this
032 * class to compare filenames.
033 *
034 * @version $Id: IOCase.java 1304052 2012-03-22 20:55:29Z ggregory $
035 * @since 1.3
036 */
037 public final class IOCase implements Serializable {
038
039 /**
040 * The constant for case sensitive regardless of operating system.
041 */
042 public static final IOCase SENSITIVE = new IOCase("Sensitive", true);
043
044 /**
045 * The constant for case insensitive regardless of operating system.
046 */
047 public static final IOCase INSENSITIVE = new IOCase("Insensitive", false);
048
049 /**
050 * The constant for case sensitivity determined by the current operating system.
051 * Windows is case-insensitive when comparing filenames, Unix is case-sensitive.
052 * <p>
053 * <strong>Note:</strong> This only caters for Windows and Unix. Other operating
054 * systems (e.g. OSX and OpenVMS) are treated as case sensitive if they use the
055 * Unix file separator and case-insensitive if they use the Windows file separator
056 * (see {@link java.io.File#separatorChar}).
057 * <p>
058 * If you derialize this constant of Windows, and deserialize on Unix, or vice
059 * versa, then the value of the case-sensitivity flag will change.
060 */
061 public static final IOCase SYSTEM = new IOCase("System", !FilenameUtils.isSystemWindows());
062
063 /** Serialization version. */
064 private static final long serialVersionUID = -6343169151696340687L;
065
066 /** The enumeration name. */
067 private final String name;
068
069 /** The sensitivity flag. */
070 private final transient boolean sensitive;
071
072 //-----------------------------------------------------------------------
073 /**
074 * Factory method to create an IOCase from a name.
075 *
076 * @param name the name to find
077 * @return the IOCase object
078 * @throws IllegalArgumentException if the name is invalid
079 */
080 public static IOCase forName(String name) {
081 if (IOCase.SENSITIVE.name.equals(name)){
082 return IOCase.SENSITIVE;
083 }
084 if (IOCase.INSENSITIVE.name.equals(name)){
085 return IOCase.INSENSITIVE;
086 }
087 if (IOCase.SYSTEM.name.equals(name)){
088 return IOCase.SYSTEM;
089 }
090 throw new IllegalArgumentException("Invalid IOCase name: " + name);
091 }
092
093 //-----------------------------------------------------------------------
094 /**
095 * Private constructor.
096 *
097 * @param name the name
098 * @param sensitive the sensitivity
099 */
100 private IOCase(String name, boolean sensitive) {
101 this.name = name;
102 this.sensitive = sensitive;
103 }
104
105 /**
106 * Replaces the enumeration from the stream with a real one.
107 * This ensures that the correct flag is set for SYSTEM.
108 *
109 * @return the resolved object
110 */
111 private Object readResolve() {
112 return forName(name);
113 }
114
115 //-----------------------------------------------------------------------
116 /**
117 * Gets the name of the constant.
118 *
119 * @return the name of the constant
120 */
121 public String getName() {
122 return name;
123 }
124
125 /**
126 * Does the object represent case sensitive comparison.
127 *
128 * @return true if case sensitive
129 */
130 public boolean isCaseSensitive() {
131 return sensitive;
132 }
133
134 //-----------------------------------------------------------------------
135 /**
136 * Compares two strings using the case-sensitivity rule.
137 * <p>
138 * This method mimics {@link String#compareTo} but takes case-sensitivity
139 * into account.
140 *
141 * @param str1 the first string to compare, not null
142 * @param str2 the second string to compare, not null
143 * @return true if equal using the case rules
144 * @throws NullPointerException if either string is null
145 */
146 public int checkCompareTo(String str1, String str2) {
147 if (str1 == null || str2 == null) {
148 throw new NullPointerException("The strings must not be null");
149 }
150 return sensitive ? str1.compareTo(str2) : str1.compareToIgnoreCase(str2);
151 }
152
153 /**
154 * Compares two strings using the case-sensitivity rule.
155 * <p>
156 * This method mimics {@link String#equals} but takes case-sensitivity
157 * into account.
158 *
159 * @param str1 the first string to compare, not null
160 * @param str2 the second string to compare, not null
161 * @return true if equal using the case rules
162 * @throws NullPointerException if either string is null
163 */
164 public boolean checkEquals(String str1, String str2) {
165 if (str1 == null || str2 == null) {
166 throw new NullPointerException("The strings must not be null");
167 }
168 return sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2);
169 }
170
171 /**
172 * Checks if one string starts with another using the case-sensitivity rule.
173 * <p>
174 * This method mimics {@link String#startsWith(String)} but takes case-sensitivity
175 * into account.
176 *
177 * @param str the string to check, not null
178 * @param start the start to compare against, not null
179 * @return true if equal using the case rules
180 * @throws NullPointerException if either string is null
181 */
182 public boolean checkStartsWith(String str, String start) {
183 return str.regionMatches(!sensitive, 0, start, 0, start.length());
184 }
185
186 /**
187 * Checks if one string ends with another using the case-sensitivity rule.
188 * <p>
189 * This method mimics {@link String#endsWith} but takes case-sensitivity
190 * into account.
191 *
192 * @param str the string to check, not null
193 * @param end the end to compare against, not null
194 * @return true if equal using the case rules
195 * @throws NullPointerException if either string is null
196 */
197 public boolean checkEndsWith(String str, String end) {
198 int endLen = end.length();
199 return str.regionMatches(!sensitive, str.length() - endLen, end, 0, endLen);
200 }
201
202 /**
203 * Checks if one string contains another starting at a specific index using the
204 * case-sensitivity rule.
205 * <p>
206 * This method mimics parts of {@link String#indexOf(String, int)}
207 * but takes case-sensitivity into account.
208 *
209 * @param str the string to check, not null
210 * @param strStartIndex the index to start at in str
211 * @param search the start to search for, not null
212 * @return the first index of the search String,
213 * -1 if no match or <code>null</code> string input
214 * @throws NullPointerException if either string is null
215 * @since 2.0
216 */
217 public int checkIndexOf(String str, int strStartIndex, String search) {
218 int endIndex = str.length() - search.length();
219 if (endIndex >= strStartIndex) {
220 for (int i = strStartIndex; i <= endIndex; i++) {
221 if (checkRegionMatches(str, i, search)) {
222 return i;
223 }
224 }
225 }
226 return -1;
227 }
228
229 /**
230 * Checks if one string contains another at a specific index using the case-sensitivity rule.
231 * <p>
232 * This method mimics parts of {@link String#regionMatches(boolean, int, String, int, int)}
233 * but takes case-sensitivity into account.
234 *
235 * @param str the string to check, not null
236 * @param strStartIndex the index to start at in str
237 * @param search the start to search for, not null
238 * @return true if equal using the case rules
239 * @throws NullPointerException if either string is null
240 */
241 public boolean checkRegionMatches(String str, int strStartIndex, String search) {
242 return str.regionMatches(!sensitive, strStartIndex, search, 0, search.length());
243 }
244
245 //-----------------------------------------------------------------------
246 /**
247 * Gets a string describing the sensitivity.
248 *
249 * @return a string describing the sensitivity
250 */
251 @Override
252 public String toString() {
253 return name;
254 }
255
256 }