18403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Copyright (c) 2011, Mike Samuel
28403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// All rights reserved.
38403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel//
48403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Redistribution and use in source and binary forms, with or without
58403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// modification, are permitted provided that the following conditions
68403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// are met:
78403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel//
88403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Redistributions of source code must retain the above copyright
98403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// notice, this list of conditions and the following disclaimer.
108403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Redistributions in binary form must reproduce the above copyright
118403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// notice, this list of conditions and the following disclaimer in the
128403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// documentation and/or other materials provided with the distribution.
138403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Neither the name of the OWASP nor the names of its contributors may
148403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// be used to endorse or promote products derived from this software
158403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// without specific prior written permission.
168403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
178403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
188403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
198403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
208403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
218403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
228403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
238403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
248403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
258403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
268403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
278403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// POSSIBILITY OF SUCH DAMAGE.
288403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel
295c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.compackage org.owasp.html;
305c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com
315c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.comimport javax.annotation.Nullable;
325c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com
335c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com/**
345c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * Locale independent versions of String case-insensitive operations.
355c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * <p>
365c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * The normal case insensitive operators {@link String#toLowerCase}
375c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * and {@link String#equalsIgnoreCase} depend upon the current locale.
385c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * They will fold the letters "i" and "I" differently if the locale is
395c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * Turkish than if it is English.
405c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * <p>
415c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * These operations ignore all case folding for non-Roman letters, and are
424e867904c8295537803c1c8a076e130df5674b58mikesamuel * independent of the current locale.
434e867904c8295537803c1c8a076e130df5674b58mikesamuel * Lower-casing is exactly equivalent to {@code tr/A-Z/a-z/}, upper-casing to
445c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * {@code tr/a-z/A-Z/}, and case insensitive comparison is equivalent to
454e867904c8295537803c1c8a076e130df5674b58mikesamuel * lower-casing both then comparing by code-unit.
465c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * <p>
475c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * Because of this simpler case folding, it is the case that for all Strings s
485c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * <code>
495c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * Strings.toUpperCase(s).equals(Strings.toUpperCase(Strings.toLowerCase(s)))
505c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com * </code>.
515c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com *
524e867904c8295537803c1c8a076e130df5674b58mikesamuel * @author Mike Samuel <mikesamuel@gmail.com>
535c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com */
544e867904c8295537803c1c8a076e130df5674b58mikesamuelfinal class Strings {
554e867904c8295537803c1c8a076e130df5674b58mikesamuel  public static boolean equalsIgnoreCase(
564e867904c8295537803c1c8a076e130df5674b58mikesamuel      @Nullable String a, @Nullable String b) {
575c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    if (a == null) { return b == null; }
585c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    if (b == null) { return false; }
595c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    int length = a.length();
605c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    if (b.length() != length) { return false; }
618560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel    for (int i = length; --i >= 0;) {
628560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel      char c = a.charAt(i), d = b.charAt(i);
638560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel      if (c != d) {
648560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel        if (c <= 'z' && c >= 'A') {
658560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel          if (c <= 'Z') { c |= 0x20; }
668560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel          if (d <= 'Z' && d >= 'A') { d |= 0x20; }
678560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel          if (c == d) { continue; }
688560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel        }
698560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel        return false;
708560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel      }
718560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel    }
728560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel    return true;
735c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  }
745c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com
755c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  public static boolean regionMatchesIgnoreCase(
768560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel      CharSequence a, int aoffset, CharSequence b, int boffset, int n) {
778560af5e2982092cb27cce62aa9cfa5bb45ea387mikesamuel    if (aoffset + n > a.length() || boffset + n > b.length()) { return false; }
785c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    for (int i = n; --i >= 0;) {
795c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      char c = a.charAt(aoffset + i), d = b.charAt(boffset + i);
805c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      if (c != d) {
815c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        if (c <= 'z' && c >= 'A') {
825c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          if (c <= 'Z') { c |= 0x20; }
835c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          if (d <= 'Z' && d >= 'A') { d |= 0x20; }
845c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          if (c == d) { continue; }
855c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        }
865c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        return false;
875c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      }
885c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    }
895c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    return true;
905c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  }
915c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com
925c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  /** True iff {@code s.equals(String.toLowerCase(s))}. */
935c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  public static boolean isLowerCase(CharSequence s) {
945c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    for (int i = s.length(); --i >= 0;) {
955c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      char c = s.charAt(i);
965c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      if (c <= 'Z' && c >= 'A') {
975c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        return false;
985c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      }
995c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    }
1005c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    return true;
1015c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  }
1025c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com
1035c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  private static final char[] LCASE_CHARS = new char['Z' + 1];
1045c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  private static final char[] UCASE_CHARS = new char['z' + 1];
1055c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  static {
1065c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    for (int i = 0; i < 'A'; ++i) { LCASE_CHARS[i] = (char) i; }
1075c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    for (int i = 'A'; i <= 'Z'; ++i) { LCASE_CHARS[i] = (char) (i | 0x20); }
1085c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    for (int i = 0; i < 'a'; ++i) { UCASE_CHARS[i] = (char) i; }
1095c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    for (int i = 'a'; i <= 'z'; ++i) { UCASE_CHARS[i] = (char) (i & ~0x20); }
1105c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  }
1115c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  public static String toLowerCase(String s) {
1125c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    for (int i = s.length(); --i >= 0;) {
1135c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      char c = s.charAt(i);
1145c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      if (c <= 'Z' && c >= 'A') {
1155c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        char[] chars = s.toCharArray();
1165c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        chars[i] = LCASE_CHARS[c];
1175c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        while (--i >= 0) {
1185c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          c = chars[i];
1195c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          if (c <= 'Z') {
1205c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com            chars[i] = LCASE_CHARS[c];
1215c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          }
1225c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        }
1235c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        return String.valueOf(chars);
1245c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      }
1255c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    }
1265c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    return s;
1275c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  }
1285c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com
1295c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  public static String toUpperCase(String s) {
1305c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    for (int i = s.length(); --i >= 0;) {
1315c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      char c = s.charAt(i);
1325c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      if (c <= 'z' && c >= 'a') {
1335c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        char[] chars = s.toCharArray();
1345c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        chars[i] = UCASE_CHARS[c];
1355c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        while (--i >= 0) {
1365c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          c = chars[i];
1375c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          if (c <= 'z') {
1385c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com            chars[i] = UCASE_CHARS[c];
1395c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com          }
1405c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        }
1415c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com        return String.valueOf(chars);
1425c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com      }
1435c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    }
1445c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com    return s;
1455c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  }
1465c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com
1475c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com  private Strings() { /* uninstantiable */ }
1485c702c12be71d8070da9287cc4a044617dd726a7manico.james@gmail.com}
149