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 */
17package org.apache.commons.io;
18
19import java.io.Serializable;
20
21/**
22 * Enumeration of IO case sensitivity.
23 * <p>
24 * Different filing systems have different rules for case-sensitivity.
25 * Windows is case-insensitive, Unix is case-sensitive.
26 * <p>
27 * This class captures that difference, providing an enumeration to
28 * control how filename comparisons should be performed. It also provides
29 * methods that use the enumeration to perform comparisons.
30 * <p>
31 * Wherever possible, you should use the <code>check</code> methods in this
32 * class to compare filenames.
33 *
34 * @author Stephen Colebourne
35 * @version $Id: IOCase.java 606345 2007-12-21 23:43:01Z ggregory $
36 * @since Commons IO 1.3
37 */
38public final class IOCase implements Serializable {
39
40    /**
41     * The constant for case sensitive regardless of operating system.
42     */
43    public static final IOCase SENSITIVE = new IOCase("Sensitive", true);
44
45    /**
46     * The constant for case insensitive regardless of operating system.
47     */
48    public static final IOCase INSENSITIVE = new IOCase("Insensitive", false);
49
50    /**
51     * The constant for case sensitivity determined by the current operating system.
52     * Windows is case-insensitive when comparing filenames, Unix is case-sensitive.
53     * <p>
54     * If you derialize this constant of Windows, and deserialize on Unix, or vice
55     * versa, then the value of the case-sensitivity flag will change.
56     */
57    public static final IOCase SYSTEM = new IOCase("System", !FilenameUtils.isSystemWindows());
58
59    /** Serialization version. */
60    private static final long serialVersionUID = -6343169151696340687L;
61
62    /** The enumeration name. */
63    private final String name;
64
65    /** The sensitivity flag. */
66    private final transient boolean sensitive;
67
68    //-----------------------------------------------------------------------
69    /**
70     * Factory method to create an IOCase from a name.
71     *
72     * @param name  the name to find
73     * @return the IOCase object
74     * @throws IllegalArgumentException if the name is invalid
75     */
76    public static IOCase forName(String name) {
77        if (IOCase.SENSITIVE.name.equals(name)){
78            return IOCase.SENSITIVE;
79        }
80        if (IOCase.INSENSITIVE.name.equals(name)){
81            return IOCase.INSENSITIVE;
82        }
83        if (IOCase.SYSTEM.name.equals(name)){
84            return IOCase.SYSTEM;
85        }
86        throw new IllegalArgumentException("Invalid IOCase name: " + name);
87    }
88
89    //-----------------------------------------------------------------------
90    /**
91     * Private constructor.
92     *
93     * @param name  the name
94     * @param sensitive  the sensitivity
95     */
96    private IOCase(String name, boolean sensitive) {
97        this.name = name;
98        this.sensitive = sensitive;
99    }
100
101    /**
102     * Replaces the enumeration from the stream with a real one.
103     * This ensures that the correct flag is set for SYSTEM.
104     *
105     * @return the resolved object
106     */
107    private Object readResolve() {
108        return forName(name);
109    }
110
111    //-----------------------------------------------------------------------
112    /**
113     * Gets the name of the constant.
114     *
115     * @return the name of the constant
116     */
117    public String getName() {
118        return name;
119    }
120
121    /**
122     * Does the object represent case sensitive comparison.
123     *
124     * @return true if case sensitive
125     */
126    public boolean isCaseSensitive() {
127        return sensitive;
128    }
129
130    //-----------------------------------------------------------------------
131    /**
132     * Compares two strings using the case-sensitivity rule.
133     * <p>
134     * This method mimics {@link String#compareTo} but takes case-sensitivity
135     * into account.
136     *
137     * @param str1  the first string to compare, not null
138     * @param str2  the second string to compare, not null
139     * @return true if equal using the case rules
140     * @throws NullPointerException if either string is null
141     */
142    public int checkCompareTo(String str1, String str2) {
143        if (str1 == null || str2 == null) {
144            throw new NullPointerException("The strings must not be null");
145        }
146        return sensitive ? str1.compareTo(str2) : str1.compareToIgnoreCase(str2);
147    }
148
149    /**
150     * Compares two strings using the case-sensitivity rule.
151     * <p>
152     * This method mimics {@link String#equals} but takes case-sensitivity
153     * into account.
154     *
155     * @param str1  the first string to compare, not null
156     * @param str2  the second string to compare, not null
157     * @return true if equal using the case rules
158     * @throws NullPointerException if either string is null
159     */
160    public boolean checkEquals(String str1, String str2) {
161        if (str1 == null || str2 == null) {
162            throw new NullPointerException("The strings must not be null");
163        }
164        return sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2);
165    }
166
167    /**
168     * Checks if one string starts with another using the case-sensitivity rule.
169     * <p>
170     * This method mimics {@link String#startsWith(String)} but takes case-sensitivity
171     * into account.
172     *
173     * @param str  the string to check, not null
174     * @param start  the start to compare against, not null
175     * @return true if equal using the case rules
176     * @throws NullPointerException if either string is null
177     */
178    public boolean checkStartsWith(String str, String start) {
179        return str.regionMatches(!sensitive, 0, start, 0, start.length());
180    }
181
182    /**
183     * Checks if one string ends with another using the case-sensitivity rule.
184     * <p>
185     * This method mimics {@link String#endsWith} but takes case-sensitivity
186     * into account.
187     *
188     * @param str  the string to check, not null
189     * @param end  the end to compare against, not null
190     * @return true if equal using the case rules
191     * @throws NullPointerException if either string is null
192     */
193    public boolean checkEndsWith(String str, String end) {
194        int endLen = end.length();
195        return str.regionMatches(!sensitive, str.length() - endLen, end, 0, endLen);
196    }
197
198    /**
199     * Checks if one string contains another at a specific index using the case-sensitivity rule.
200     * <p>
201     * This method mimics parts of {@link String#regionMatches(boolean, int, String, int, int)}
202     * but takes case-sensitivity into account.
203     *
204     * @param str  the string to check, not null
205     * @param strStartIndex  the index to start at in str
206     * @param search  the start to search for, not null
207     * @return true if equal using the case rules
208     * @throws NullPointerException if either string is null
209     */
210    public boolean checkRegionMatches(String str, int strStartIndex, String search) {
211        return str.regionMatches(!sensitive, strStartIndex, search, 0, search.length());
212    }
213
214    /**
215     * Converts the case of the input String to a standard format.
216     * Subsequent operations can then use standard String methods.
217     *
218     * @param str  the string to convert, null returns null
219     * @return the lower-case version if case-insensitive
220     */
221    String convertCase(String str) {
222        if (str == null) {
223            return null;
224        }
225        return sensitive ? str : str.toLowerCase();
226    }
227
228    //-----------------------------------------------------------------------
229    /**
230     * Gets a string describing the sensitivity.
231     *
232     * @return a string describing the sensitivity
233     */
234    public String toString() {
235        return name;
236    }
237
238}
239