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     * @author Stephen Colebourne
035     * @version $Id: IOCase.java 606345 2007-12-21 23:43:01Z ggregory $
036     * @since Commons IO 1.3
037     */
038    public final class IOCase implements Serializable {
039    
040        /**
041         * The constant for case sensitive regardless of operating system.
042         */
043        public static final IOCase SENSITIVE = new IOCase("Sensitive", true);
044        
045        /**
046         * The constant for case insensitive regardless of operating system.
047         */
048        public static final IOCase INSENSITIVE = new IOCase("Insensitive", false);
049        
050        /**
051         * The constant for case sensitivity determined by the current operating system.
052         * Windows is case-insensitive when comparing filenames, Unix is case-sensitive.
053         * <p>
054         * If you derialize this constant of Windows, and deserialize on Unix, or vice
055         * versa, then the value of the case-sensitivity flag will change.
056         */
057        public static final IOCase SYSTEM = new IOCase("System", !FilenameUtils.isSystemWindows());
058    
059        /** Serialization version. */
060        private static final long serialVersionUID = -6343169151696340687L;
061    
062        /** The enumeration name. */
063        private final String name;
064        
065        /** The sensitivity flag. */
066        private final transient boolean sensitive;
067    
068        //-----------------------------------------------------------------------
069        /**
070         * Factory method to create an IOCase from a name.
071         * 
072         * @param name  the name to find
073         * @return the IOCase object
074         * @throws IllegalArgumentException if the name is invalid
075         */
076        public static IOCase forName(String name) {
077            if (IOCase.SENSITIVE.name.equals(name)){
078                return IOCase.SENSITIVE;
079            }
080            if (IOCase.INSENSITIVE.name.equals(name)){
081                return IOCase.INSENSITIVE;
082            }
083            if (IOCase.SYSTEM.name.equals(name)){
084                return IOCase.SYSTEM;
085            }
086            throw new IllegalArgumentException("Invalid IOCase name: " + name);
087        }
088    
089        //-----------------------------------------------------------------------
090        /**
091         * Private constructor.
092         * 
093         * @param name  the name
094         * @param sensitive  the sensitivity
095         */
096        private IOCase(String name, boolean sensitive) {
097            this.name = name;
098            this.sensitive = sensitive;
099        }
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    }