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 */ 017package org.apache.commons.vfs2.filter; 018 019import java.io.File; 020import java.util.Objects; 021 022/** 023 * Enumeration of IO case sensitivity. 024 * <p> 025 * Different filing systems have different rules for case-sensitivity. Windows 026 * is case-insensitive, Unix is case-sensitive. 027 * </p> 028 * <p> 029 * This class captures that difference, providing an enumeration to control how 030 * file name comparisons should be performed. It also provides methods that use 031 * the enumeration to perform comparisons. 032 * </p> 033 * <p> 034 * Wherever possible, you should use the {@code check} methods in this 035 * class to compare file names. 036 * </p> 037 * 038 * @author This code was originally ported from Apache Commons IO File Filter 039 * @see "https://commons.apache.org/proper/commons-io/" 040 * @since 2.4 041 */ 042public enum IOCase { 043 044 /** 045 * The constant for case-sensitive regardless of operating system. 046 */ 047 SENSITIVE("Sensitive", true), 048 049 /** 050 * The constant for case-insensitive regardless of operating system. 051 */ 052 INSENSITIVE("Insensitive", false), 053 054 /** 055 * The constant for case sensitivity determined by the current operating system. 056 * Windows is case-insensitive when comparing file names, Unix is case-sensitive. 057 * <p> 058 * <strong>Note:</strong> This only caters for Windows and Unix. Other operating 059 * systems (e.g. OSX and OpenVMS) are treated as case-sensitive if they use the 060 * Unix file separator and case-insensitive if they use the Windows file 061 * separator (see {@link File#separatorChar}). 062 * <p> 063 * If you serialize this constant on Windows, and deserialize on Unix, or vice 064 * versa, then the value of the case-sensitivity flag will change. 065 */ 066 SYSTEM("System", !(File.separatorChar == '\\')); 067 068 /** Serialization version. */ 069 private static final long serialVersionUID = -6343169151696340687L; 070 071 /** 072 * Factory method to create an IOCase from a name. 073 * 074 * @param name the name to find 075 * @return the IOCase object 076 * @throws IllegalArgumentException if the name is invalid 077 */ 078 public static IOCase forName(final String name) { 079 for (final IOCase ioCase : values()) { 080 if (ioCase.getName().equals(name)) { 081 return ioCase; 082 } 083 } 084 throw new IllegalArgumentException("Invalid IOCase name: " + name); 085 } 086 087 /** The enumeration name. */ 088 private final String name; 089 090 /** The sensitivity flag. */ 091 private final transient boolean sensitive; 092 093 /** 094 * Constructs a new instance. 095 * 096 * @param name the name 097 * @param sensitive the sensitivity 098 */ 099 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}