    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 1003647 2010-10-01 20:53:59Z niallp $
    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         * <strong>Note:</strong> This only caters for Windows and Unix. Other operating
    055         * systems (e.g. OSX and OpenVMS) are treated as case sensitive if they use the
    056         * Unix file separator and case-insensitive if they use the Windows file separator
    057         * (see {@link java.io.File#separatorChar}).
    058         * <p>
    059         * If you derialize this constant of Windows, and deserialize on Unix, or vice
    060         * versa, then the value of the case-sensitivity flag will change.
    061         */
    062        public static final IOCase SYSTEM = new IOCase("System", !FilenameUtils.isSystemWindows());
    063
    064        /** Serialization version. */
    065        private static final long serialVersionUID = -6343169151696340687L;
    066
    067        /** The enumeration name. */
    068        private final String name;
    069
    070        /** The sensitivity flag. */
    071        private final transient boolean sensitive;
    072
    073        //-----------------------------------------------------------------------
    074        /**
    075         * Factory method to create an IOCase from a name.
    076         *
    077         * @param name  the name to find
    078         * @return the IOCase object
    079         * @throws IllegalArgumentException if the name is invalid
    080         */
    081        public static IOCase forName(String name) {
    082            if (IOCase.SENSITIVE.name.equals(name)){
    083                return IOCase.SENSITIVE;
    084            }
    085            if (IOCase.INSENSITIVE.name.equals(name)){
    086                return IOCase.INSENSITIVE;
    087            }
    088            if (IOCase.SYSTEM.name.equals(name)){
    089                return IOCase.SYSTEM;
    090            }
    091            throw new IllegalArgumentException("Invalid IOCase name: " + name);
    092        }
    093
    094        //-----------------------------------------------------------------------
    095        /**
    096         * Private constructor.
    097         *
    098         * @param name  the name
    099         * @param sensitive  the sensitivity
    100         */
    101        private IOCase(String name, boolean sensitive) {
    102            this.name = name;
    103            this.sensitive = sensitive;
    104        }
    105
    106        /**
    107         * Replaces the enumeration from the stream with a real one.
    108         * This ensures that the correct flag is set for SYSTEM.
    109         *
    110         * @return the resolved object
    111         */
    112        private Object readResolve() {
    113            return forName(name);
    114        }
    115
    116        //-----------------------------------------------------------------------
    117        /**
    118         * Gets the name of the constant.
    119         *
    120         * @return the name of the constant
    121         */
    122        public String getName() {
    123            return name;
    124        }
    125
    126        /**
    127         * Does the object represent case sensitive comparison.
    128         *
    129         * @return true if case sensitive
    130         */
    131        public boolean isCaseSensitive() {
    132            return sensitive;
    133        }
    134
    135        //-----------------------------------------------------------------------
    136        /**
    137         * Compares two strings using the case-sensitivity rule.
    138         * <p>
    139         * This method mimics {@link String#compareTo} but takes case-sensitivity
    140         * into account.
    141         *
    142         * @param str1  the first string to compare, not null
    143         * @param str2  the second string to compare, not null
    144         * @return true if equal using the case rules
    145         * @throws NullPointerException if either string is null
    146         */
    147        public int checkCompareTo(String str1, String str2) {
    148            if (str1 == null || str2 == null) {
    149                throw new NullPointerException("The strings must not be null");
    150            }
    151            return sensitive ? str1.compareTo(str2) : str1.compareToIgnoreCase(str2);
    152        }
    153
    154        /**
    155         * Compares two strings using the case-sensitivity rule.
    156         * <p>
    157         * This method mimics {@link String#equals} but takes case-sensitivity
    158         * into account.
    159         *
    160         * @param str1  the first string to compare, not null
    161         * @param str2  the second string to compare, not null
    162         * @return true if equal using the case rules
    163         * @throws NullPointerException if either string is null
    164         */
    165        public boolean checkEquals(String str1, String str2) {
    166            if (str1 == null || str2 == null) {
    167                throw new NullPointerException("The strings must not be null");
    168            }
    169            return sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2);
    170        }
    171
    172        /**
    173         * Checks if one string starts with another using the case-sensitivity rule.
    174         * <p>
    175         * This method mimics {@link String#startsWith(String)} but takes case-sensitivity
    176         * into account.
    177         *
    178         * @param str  the string to check, not null
    179         * @param start  the start to compare against, not null
    180         * @return true if equal using the case rules
    181         * @throws NullPointerException if either string is null
    182         */
    183        public boolean checkStartsWith(String str, String start) {
    184            return str.regionMatches(!sensitive, 0, start, 0, start.length());
    185        }
    186
    187        /**
    188         * Checks if one string ends with another using the case-sensitivity rule.
    189         * <p>
    190         * This method mimics {@link String#endsWith} but takes case-sensitivity
    191         * into account.
    192         *
    193         * @param str  the string to check, not null
    194         * @param end  the end to compare against, not null
    195         * @return true if equal using the case rules
    196         * @throws NullPointerException if either string is null
    197         */
    198        public boolean checkEndsWith(String str, String end) {
    199            int endLen = end.length();
    200            return str.regionMatches(!sensitive, str.length() - endLen, end, 0, endLen);
    201        }
    202
    203        /**
    204         * Checks if one string contains another starting at a specific index using the
    205         * case-sensitivity rule.
    206         * <p>
    207         * This method mimics parts of {@link String#indexOf(String, int)}
    208         * but takes case-sensitivity into account.
    209         *
    210         * @param str  the string to check, not null
    211         * @param strStartIndex  the index to start at in str
    212         * @param search  the start to search for, not null
    213         * @return the first index of the search String,
    214         *  -1 if no match or <code>null</code> string input
    215         * @throws NullPointerException if either string is null
    216         * @since Commons IO 2.0
    217         */
    218        public int checkIndexOf(String str, int strStartIndex, String search) {
    219            int endIndex = str.length() - search.length();
    220            if (endIndex >= strStartIndex) {
    221                for (int i = strStartIndex; i <= endIndex; i++) {
    222                    if (checkRegionMatches(str, i, search)) {
    223                        return i;
    224                    }
    225                }
    226            }
    227            return -1;
    228        }
    229
    230        /**
    231         * Checks if one string contains another at a specific index using the case-sensitivity rule.
    232         * <p>
    233         * This method mimics parts of {@link String#regionMatches(boolean, int, String, int, int)}
    234         * but takes case-sensitivity into account.
    235         *
    236         * @param str  the string to check, not null
    237         * @param strStartIndex  the index to start at in str
    238         * @param search  the start to search for, not null
    239         * @return true if equal using the case rules
    240         * @throws NullPointerException if either string is null
    241         */
    242        public boolean checkRegionMatches(String str, int strStartIndex, String search) {
    243            return str.regionMatches(!sensitive, strStartIndex, search, 0, search.length());
    244        }
    245
    246        //-----------------------------------------------------------------------
    247        /**
    248         * Gets a string describing the sensitivity.
    249         *
    250         * @return a string describing the sensitivity
    251         */
    252        @Override
    253        public String toString() {
    254            return name;
    255        }
    256
    257    }