1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang;
  27 
  28 import java.util.Arrays;
  29 import java.util.Locale;
  30 import java.util.Spliterator;
  31 import java.util.function.IntConsumer;
  32 import jdk.internal.HotSpotIntrinsicCandidate;
  33 
  34 import static java.lang.String.UTF16;
  35 import static java.lang.String.LATIN1;
  36 import static java.lang.String.checkIndex;
  37 import static java.lang.String.checkOffset;
  38 import static java.lang.String.checkBoundsOffCount;
  39 import static java.lang.String.checkBoundsBeginEnd;
  40 
  41 final class StringUTF16 {
  42 
  43     public static byte[] newBytesFor(int len) {
  44         if (len < 0) {
  45             throw new NegativeArraySizeException();
  46         }
  47         if (len > MAX_LENGTH) {
  48             throw new OutOfMemoryError("UTF16 String size is " + len +
  49                                        ", should be less than " + MAX_LENGTH);
  50         }
  51         return new byte[len << 1];
  52     }
  53 
  54     @HotSpotIntrinsicCandidate
  55     public static void putChar(byte[] val, int index, int c) {
  56         index <<= 1;
  57         val[index++] = (byte)(c >> HI_BYTE_SHIFT);
  58         val[index]   = (byte)(c >> LO_BYTE_SHIFT);
  59     }
  60 
  61     @HotSpotIntrinsicCandidate
  62     public static char getChar(byte[] val, int index) {
  63         index <<= 1;
  64         return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
  65                       ((val[index]   & 0xff) << LO_BYTE_SHIFT));
  66     }
  67 
  68     public static char charAt(byte[] value, int index) {
  69         if (index < 0 || index >= value.length >> 1) {
  70             throw new StringIndexOutOfBoundsException(index);
  71         }
  72         return getChar(value, index);
  73     }
  74 
  75     public static int length(byte[] value) {
  76         return value.length >> 1;
  77     }
  78 
  79     public static int codePointAt(byte[] value, int index, int end) {
  80         char c1 = getChar(value, index);
  81         if (Character.isHighSurrogate(c1) && ++index < end) {
  82             char c2 = getChar(value, index);
  83             if (Character.isLowSurrogate(c2)) {
  84                return Character.toCodePoint(c1, c2);
  85             }
  86         }
  87         return c1;
  88     }
  89 
  90     public static int codePointBefore(byte[] value, int index) {
  91         char c2 = getChar(value, --index);
  92         if (Character.isLowSurrogate(c2) && index > 0) {
  93             char c1 = getChar(value, --index);
  94             if (Character.isHighSurrogate(c1)) {
  95                return Character.toCodePoint(c1, c2);
  96             }
  97         }
  98         return c2;
  99     }
 100 
 101     public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
 102         int count = endIndex - beginIndex;
 103         for (int i = beginIndex; i < endIndex; ) {
 104             if (Character.isHighSurrogate(getChar(value, i++)) &&
 105                 i < endIndex &&
 106                 Character.isLowSurrogate(getChar(value, i))) {
 107                 count--;
 108                 i++;
 109             }
 110         }
 111         return count;
 112     }
 113 
 114     public static char[] toChars(byte[] value) {
 115         char[] dst = new char[value.length >> 1];
 116         getChars(value, 0, dst.length, dst, 0);
 117         return dst;
 118     }
 119 
 120     @HotSpotIntrinsicCandidate
 121     public static byte[] toBytes(char[] value, int off, int len) {
 122         byte[] val = newBytesFor(len);
 123         for (int i = 0; i < len; i++) {
 124             putChar(val, i, value[off]);
 125             off++;
 126         }
 127         return val;
 128     }
 129 
 130     public static byte[] compress(char[] val, int off, int len) {
 131         byte[] ret = new byte[len];
 132         if (compress(val, off, ret, 0, len) == len) {
 133             return ret;
 134         }
 135         return null;
 136     }
 137 
 138     public static byte[] compress(byte[] val, int off, int len) {
 139         byte[] ret = new byte[len];
 140         if (compress(val, off, ret, 0, len) == len) {
 141             return ret;
 142         }
 143         return null;
 144     }
 145 
 146     // compressedCopy char[] -> byte[]
 147     @HotSpotIntrinsicCandidate
 148     public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
 149         for (int i = 0; i < len; i++) {
 150             char c = src[srcOff];
 151             if (c > 0xFF) {
 152                 len = 0;
 153                 break;
 154             }
 155             dst[dstOff] = (byte)c;
 156             srcOff++;
 157             dstOff++;
 158         }
 159         return len;
 160     }
 161 
 162     // compressedCopy byte[] -> byte[]
 163     @HotSpotIntrinsicCandidate
 164     public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
 165         // We need a range check here because 'getChar' has no checks
 166         checkBoundsOffCount(srcOff << 1, len << 1, src.length);
 167         for (int i = 0; i < len; i++) {
 168             char c = getChar(src, srcOff);
 169             if (c > 0xFF) {
 170                 len = 0;
 171                 break;
 172             }
 173             dst[dstOff] = (byte)c;
 174             srcOff++;
 175             dstOff++;
 176         }
 177         return len;
 178     }
 179 
 180     public static byte[] toBytes(int[] val, int index, int len) {
 181         final int end = index + len;
 182         // Pass 1: Compute precise size of char[]
 183         int n = len;
 184         for (int i = index; i < end; i++) {
 185             int cp = val[i];
 186             if (Character.isBmpCodePoint(cp))
 187                 continue;
 188             else if (Character.isValidCodePoint(cp))
 189                 n++;
 190             else throw new IllegalArgumentException(Integer.toString(cp));
 191         }
 192         // Pass 2: Allocate and fill in <high, low> pair
 193         byte[] buf = newBytesFor(n);
 194         for (int i = index, j = 0; i < end; i++, j++) {
 195             int cp = val[i];
 196             if (Character.isBmpCodePoint(cp)) {
 197                 putChar(buf, j, cp);
 198             } else {
 199                 putChar(buf, j++, Character.highSurrogate(cp));
 200                 putChar(buf, j, Character.lowSurrogate(cp));
 201             }
 202         }
 203         return buf;
 204     }
 205 
 206     public static byte[] toBytes(char c) {
 207         byte[] result = new byte[2];
 208         putChar(result, 0, c);
 209         return result;
 210     }
 211 
 212     @HotSpotIntrinsicCandidate
 213     public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
 214         // We need a range check here because 'getChar' has no checks
 215         if (srcBegin < srcEnd) {
 216             checkBoundsOffCount(srcBegin << 1, (srcEnd - srcBegin) << 1, value.length);
 217         }
 218         for (int i = srcBegin; i < srcEnd; i++) {
 219             dst[dstBegin++] = getChar(value, i);
 220         }
 221     }
 222 
 223     /* @see java.lang.String.getBytes(int, int, byte[], int) */
 224     public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
 225         srcBegin <<= 1;
 226         srcEnd <<= 1;
 227         for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) {
 228             dst[dstBegin++] = value[i];
 229         }
 230     }
 231 
 232     @HotSpotIntrinsicCandidate
 233     public static boolean equals(byte[] value, byte[] other) {
 234         if (value.length == other.length) {
 235             int len = value.length >> 1;
 236             for (int i = 0; i < len; i++) {
 237                 if (getChar(value, i) != getChar(other, i)) {
 238                     return false;
 239                 }
 240             }
 241             return true;
 242         }
 243         return false;
 244     }
 245 
 246     @HotSpotIntrinsicCandidate
 247     public static int compareTo(byte[] value, byte[] other) {
 248         int len1 = length(value);
 249         int len2 = length(other);
 250         int lim = Math.min(len1, len2);
 251         for (int k = 0; k < lim; k++) {
 252             char c1 = getChar(value, k);
 253             char c2 = getChar(other, k);
 254             if (c1 != c2) {
 255                 return c1 - c2;
 256             }
 257         }
 258         return len1 - len2;
 259     }
 260 
 261     @HotSpotIntrinsicCandidate
 262     public static int compareToLatin1(byte[] value, byte[] other) {
 263         return -StringLatin1.compareToUTF16(other, value);
 264     }
 265 
 266     public static int compareToCI(byte[] value, byte[] other) {
 267         int len1 = length(value);
 268         int len2 = length(other);
 269         int lim = Math.min(len1, len2);
 270         for (int k = 0; k < lim; k++) {
 271             char c1 = getChar(value, k);
 272             char c2 = getChar(other, k);
 273             if (c1 != c2) {
 274                 c1 = Character.toUpperCase(c1);
 275                 c2 = Character.toUpperCase(c2);
 276                 if (c1 != c2) {
 277                     c1 = Character.toLowerCase(c1);
 278                     c2 = Character.toLowerCase(c2);
 279                     if (c1 != c2) {
 280                         return c1 - c2;
 281                     }
 282                 }
 283             }
 284         }
 285         return len1 - len2;
 286     }
 287 
 288     public static int compareToCI_Latin1(byte[] value, byte[] other) {
 289         return -StringLatin1.compareToCI_UTF16(other, value);
 290     }
 291 
 292     public static int hashCode(byte[] value) {
 293         int h = 0;
 294         int length = value.length >> 1;
 295         for (int i = 0; i < length; i++) {
 296             h = 31 * h + getChar(value, i);
 297         }
 298         return h;
 299     }
 300 
 301     public static int indexOf(byte[] value, int ch, int fromIndex) {
 302         int max = value.length >> 1;
 303         if (fromIndex < 0) {
 304             fromIndex = 0;
 305         } else if (fromIndex >= max) {
 306             // Note: fromIndex might be near -1>>>1.
 307             return -1;
 308         }
 309         if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
 310             // handle most cases here (ch is a BMP code point or a
 311             // negative value (invalid code point))
 312             return indexOfChar(value, ch, fromIndex, max);
 313         } else {
 314             return indexOfSupplementary(value, ch, fromIndex, max);
 315         }
 316     }
 317 
 318     @HotSpotIntrinsicCandidate
 319     public static int indexOf(byte[] value, byte[] str) {
 320         if (str.length == 0) {
 321             return 0;
 322         }
 323         if (value.length == 0) {
 324             return -1;
 325         }
 326         return indexOf(value, length(value), str, length(str), 0);
 327     }
 328 
 329     @HotSpotIntrinsicCandidate
 330     public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
 331         // Redundant.
 332         // Callers:
 333         //   StringUTF16.indexOf(byte[] value, byte[] str): valid by construction
 334         //     return indexOf(value, length(value), str, length(str), 0);
 335         //
 336         //   String.indexOf:
 337         //     StringUTF16.indexOf(src, srcCount, tgt, tgtCount, fromIndex);
 338         //     0 <= tgtCount < tgtStr.length >> 1
 339         //        byte[] tgt    = tgtStr.value;
 340         //        int tgtCount  = tgtStr.length();
 341         //
 342         //     0 < fromIndex < srcCount
 343         //
 344         //     0 <= srcCount < src.length
 345         //     Covered by ABS.indexOf():
 346         //        checkIndex(count, value.length >> coder);
 347         //        return String.indexOf(value, coder, count, str, fromIndex);
 348         checkBoundsBeginEnd(fromIndex, valueCount, value.length >> 1);
 349         checkBoundsBeginEnd(0, strCount, str.length >> 1);
 350 
 351         char first = getChar(str, 0);
 352         int max = (valueCount - strCount);
 353         for (int i = fromIndex; i <= max; i++) {
 354             // Look for first character.
 355             if (getChar(value, i) != first) {
 356                 while (++i <= max && getChar(value, i) != first);
 357             }
 358             // Found first character, now look at the rest of value
 359             if (i <= max) {
 360                 int j = i + 1;
 361                 int end = j + strCount - 1;
 362                 for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++);
 363                 if (j == end) {
 364                     // Found whole string.
 365                     return i;
 366                 }
 367             }
 368         }
 369         return -1;
 370     }
 371 
 372     /**
 373      * Handles indexOf Latin1 substring in UTF16 string.
 374      */
 375     @HotSpotIntrinsicCandidate
 376     public static int indexOfLatin1(byte[] value, byte[] str) {
 377         if (str.length == 0) {
 378             return 0;
 379         }
 380         if (value.length == 0) {
 381             return -1;
 382         }
 383         return indexOfLatin1(value, length(value), str, str.length, 0);
 384     }
 385 
 386     @HotSpotIntrinsicCandidate
 387     public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
 388         // Redundant (similar to StringUTF16.indexOf).
 389         checkBoundsBeginEnd(fromIndex, srcCount, src.length >> 1);
 390         checkBoundsBeginEnd(0, tgtCount, tgt.length >> 1);
 391 
 392         char first = (char)(tgt[0] & 0xff);
 393         int max = (srcCount - tgtCount);
 394         for (int i = fromIndex; i <= max; i++) {
 395             // Look for first character.
 396             if (getChar(src, i) != first) {
 397                 while (++i <= max && getChar(src, i) != first);
 398             }
 399             // Found first character, now look at the rest of v2
 400             if (i <= max) {
 401                 int j = i + 1;
 402                 int end = j + tgtCount - 1;
 403                 for (int k = 1;
 404                      j < end && getChar(src, j) == (tgt[k] & 0xff);
 405                      j++, k++);
 406                 if (j == end) {
 407                     // Found whole string.
 408                     return i;
 409                 }
 410             }
 411         }
 412         return -1;
 413     }
 414 
 415     @HotSpotIntrinsicCandidate
 416     private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) {
 417         // Redundant: StringUTF16.indexOf (caller) does the checks
 418         //   max == value.length >> 1
 419         //   0 <= fromIndex <= max
 420         checkBoundsBeginEnd(fromIndex, max, value.length >> 1);
 421         for (int i = fromIndex; i < max; i++) {
 422             if (getChar(value, i) == ch) {
 423                 return i;
 424             }
 425         }
 426         return -1;
 427     }
 428 
 429     /**
 430      * Handles (rare) calls of indexOf with a supplementary character.
 431      */
 432     private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) {
 433         if (Character.isValidCodePoint(ch)) {
 434             final char hi = Character.highSurrogate(ch);
 435             final char lo = Character.lowSurrogate(ch);
 436             // Redundant: StringUTF16.indexOf (caller) does the checks
 437             //   max == value.length >> 1
 438             //   0 <= fromIndex <= max
 439             checkBoundsBeginEnd(fromIndex, max, value.length >> 1);
 440             for (int i = fromIndex; i < max - 1; i++) {
 441                 if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) {
 442                     return i;
 443                 }
 444             }
 445         }
 446         return -1;
 447     }
 448 
 449     // srcCoder == UTF16 && tgtCoder == UTF16
 450     public static int lastIndexOf(byte[] src, int srcCount,
 451                                   byte[] tgt, int tgtCount, int fromIndex) {
 452         int min = tgtCount - 1;
 453         int i = min + fromIndex;
 454         int strLastIndex = tgtCount - 1;
 455 
 456         // Redundant: covered by checks in String.lastIndexOf
 457         checkIndex(strLastIndex, tgt.length >> 1);
 458         char strLastChar = getChar(tgt, strLastIndex);
 459 
 460         // Redundant: not needed for String.lastIndexOf(), covered by ASB.lastIndexOf().
 461         checkIndex(i, src.length >> 1);
 462 
 463     startSearchForLastChar:
 464         while (true) {
 465             while (i >= min && getChar(src, i) != strLastChar) {
 466                 i--;
 467             }
 468             if (i < min) {
 469                 return -1;
 470             }
 471             int j = i - 1;
 472             int start = j - strLastIndex;
 473             int k = strLastIndex - 1;
 474             while (j > start) {
 475                 if (getChar(src, j--) != getChar(tgt, k--)) {
 476                     i--;
 477                     continue startSearchForLastChar;
 478                 }
 479             }
 480             return start + 1;
 481         }
 482     }
 483 
 484     public static int lastIndexOf(byte[] value, int ch, int fromIndex) {
 485         if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
 486             // handle most cases here (ch is a BMP code point or a
 487             // negative value (invalid code point))
 488             int i = Math.min(fromIndex, (value.length >> 1) - 1);
 489             for (; i >= 0; i--) {
 490                 if (getChar(value, i) == ch) {
 491                     return i;
 492                 }
 493             }
 494             return -1;
 495         } else {
 496             return lastIndexOfSupplementary(value, ch, fromIndex);
 497         }
 498     }
 499 
 500     /**
 501      * Handles (rare) calls of lastIndexOf with a supplementary character.
 502      */
 503     private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) {
 504         if (Character.isValidCodePoint(ch)) {
 505             char hi = Character.highSurrogate(ch);
 506             char lo = Character.lowSurrogate(ch);
 507             int i = Math.min(fromIndex, (value.length >> 1) - 2);
 508             for (; i >= 0; i--) {
 509                 if (getChar(value, i) == hi && getChar(value, i + 1) == lo) {
 510                     return i;
 511                 }
 512             }
 513         }
 514         return -1;
 515     }
 516 
 517     public static String replace(byte[] value, char oldChar, char newChar) {
 518         int len = value.length >> 1;
 519         int i = -1;
 520         while (++i < len) {
 521             if (getChar(value, i) == oldChar) {
 522                 break;
 523             }
 524         }
 525         if (i < len) {
 526             byte buf[] = new byte[value.length];
 527             for (int j = 0; j < i; j++) {
 528                 putChar(buf, j, getChar(value, j)); // TBD:arraycopy?
 529             }
 530             while (i < len) {
 531                 char c = getChar(value, i);
 532                 putChar(buf, i, c == oldChar ? newChar : c);
 533                 i++;
 534            }
 535            // Check if we should try to compress to latin1
 536            if (String.COMPACT_STRINGS &&
 537                !StringLatin1.canEncode(oldChar) &&
 538                StringLatin1.canEncode(newChar)) {
 539                byte[] val = compress(buf, 0, len);
 540                if (val != null) {
 541                    return new String(val, LATIN1);
 542                }
 543            }
 544            return new String(buf, UTF16);
 545         }
 546         return null;
 547     }
 548 
 549     public static boolean regionMatchesCI(byte[] value, int toffset,
 550                                           byte[] other, int ooffset, int len) {
 551         int last = toffset + len;
 552         while (toffset < last) {
 553             char c1 = getChar(value, toffset++);
 554             char c2 = getChar(other, ooffset++);
 555             if (c1 == c2) {
 556                 continue;
 557             }
 558             // try converting both characters to uppercase.
 559             // If the results match, then the comparison scan should
 560             // continue.
 561             char u1 = Character.toUpperCase(c1);
 562             char u2 = Character.toUpperCase(c2);
 563             if (u1 == u2) {
 564                 continue;
 565             }
 566             // Unfortunately, conversion to uppercase does not work properly
 567             // for the Georgian alphabet, which has strange rules about case
 568             // conversion.  So we need to make one last check before
 569             // exiting.
 570             if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
 571                 continue;
 572             }
 573             return false;
 574         }
 575         return true;
 576     }
 577 
 578     public static boolean regionMatchesCI_Latin1(byte[] value, int toffset,
 579                                                  byte[] other, int ooffset,
 580                                                  int len) {
 581         return StringLatin1.regionMatchesCI_UTF16(other, ooffset, value, toffset, len);
 582     }
 583 
 584     public static String toLowerCase(String str, byte[] value, Locale locale) {
 585         if (locale == null) {
 586             throw new NullPointerException();
 587         }
 588         int first;
 589         boolean hasSurr = false;
 590         final int len = value.length >> 1;
 591 
 592         // Now check if there are any characters that need to be changed, or are surrogate
 593         for (first = 0 ; first < len; first++) {
 594             int cp = (int)getChar(value, first);
 595             if (Character.isSurrogate((char)cp)) {
 596                 hasSurr = true;
 597                 break;
 598             }
 599             if (cp != Character.toLowerCase(cp)) {  // no need to check Character.ERROR
 600                 break;
 601             }
 602         }
 603         if (first == len)
 604             return str;
 605         byte[] result = new byte[value.length];
 606         System.arraycopy(value, 0, result, 0, first << 1);  // Just copy the first few
 607                                                             // lowerCase characters.
 608         String lang = locale.getLanguage();
 609         if (lang == "tr" || lang == "az" || lang == "lt") {
 610             return toLowerCaseEx(str, value, result, first, locale, true);
 611         }
 612         if (hasSurr) {
 613             return toLowerCaseEx(str, value, result, first, locale, false);
 614         }
 615         int bits = 0;
 616         for (int i = first; i < len; i++) {
 617             int cp = (int)getChar(value, i);
 618             if (cp == '\u03A3' ||                       // GREEK CAPITAL LETTER SIGMA
 619                 Character.isSurrogate((char)cp)) {
 620                 return toLowerCaseEx(str, value, result, i, locale, false);
 621             }
 622             if (cp == '\u0130') {                       // LATIN CAPITAL LETTER I WITH DOT ABOVE
 623                 return toLowerCaseEx(str, value, result, i, locale, true);
 624             }
 625             cp = Character.toLowerCase(cp);
 626             if (!Character.isBmpCodePoint(cp)) {
 627                 return toLowerCaseEx(str, value, result, i, locale, false);
 628             }
 629             bits |= cp;
 630             putChar(result, i, cp);
 631         }
 632         if (bits > 0xFF) {
 633             return new String(result, UTF16);
 634         } else {
 635             return newString(result, 0, len);
 636         }
 637     }
 638 
 639     private static String toLowerCaseEx(String str, byte[] value,
 640                                         byte[] result, int first, Locale locale,
 641                                         boolean localeDependent) {
 642         int resultOffset = first;
 643         int length = value.length >> 1;
 644         int srcCount;
 645         for (int i = first; i < length; i += srcCount) {
 646             int srcChar = getChar(value, i);
 647             int lowerChar;
 648             char[] lowerCharArray;
 649             srcCount = 1;
 650             if (Character.isSurrogate((char)srcChar)) {
 651                 srcChar = codePointAt(value, i, length);
 652                 srcCount = Character.charCount(srcChar);
 653             }
 654             if (localeDependent ||
 655                 srcChar == '\u03A3' ||  // GREEK CAPITAL LETTER SIGMA
 656                 srcChar == '\u0130') {  // LATIN CAPITAL LETTER I WITH DOT ABOVE
 657                 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
 658             } else {
 659                 lowerChar = Character.toLowerCase(srcChar);
 660             }
 661             if (Character.isBmpCodePoint(lowerChar)) {    // Character.ERROR is not a bmp
 662                 putChar(result, resultOffset++, lowerChar);
 663             } else {
 664                 if (lowerChar == Character.ERROR) {
 665                     lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
 666                 } else {
 667                     lowerCharArray = Character.toChars(lowerChar);
 668                 }
 669                 /* Grow result if needed */
 670                 int mapLen = lowerCharArray.length;
 671                 if (mapLen > srcCount) {
 672                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 673                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 674                     result = result2;
 675                 }
 676                 for (int x = 0; x < mapLen; ++x) {
 677                     putChar(result, resultOffset++, lowerCharArray[x]);
 678                 }
 679             }
 680         }
 681         return newString(result, 0, resultOffset);
 682     }
 683 
 684     public static String toUpperCase(String str, byte[] value, Locale locale) {
 685         if (locale == null) {
 686             throw new NullPointerException();
 687         }
 688         int first;
 689         boolean hasSurr = false;
 690         final int len = value.length >> 1;
 691 
 692         // Now check if there are any characters that need to be changed, or are surrogate
 693         for (first = 0 ; first < len; first++) {
 694             int cp = (int)getChar(value, first);
 695             if (Character.isSurrogate((char)cp)) {
 696                 hasSurr = true;
 697                 break;
 698             }
 699             if (cp != Character.toUpperCaseEx(cp)) {   // no need to check Character.ERROR
 700                 break;
 701             }
 702         }
 703         if (first == len) {
 704             return str;
 705         }
 706         byte[] result = new byte[value.length];
 707         System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
 708                                                            // upperCase characters.
 709         String lang = locale.getLanguage();
 710         if (lang == "tr" || lang == "az" || lang == "lt") {
 711             return toUpperCaseEx(str, value, result, first, locale, true);
 712         }
 713         if (hasSurr) {
 714             return toUpperCaseEx(str, value, result, first, locale, false);
 715         }
 716         int bits = 0;
 717         for (int i = first; i < len; i++) {
 718             int cp = (int)getChar(value, i);
 719             if (Character.isSurrogate((char)cp)) {
 720                 return toUpperCaseEx(str, value, result, i, locale, false);
 721             }
 722             cp = Character.toUpperCaseEx(cp);
 723             if (!Character.isBmpCodePoint(cp)) {    // Character.ERROR is not bmp
 724                 return toUpperCaseEx(str, value, result, i, locale, false);
 725             }
 726             bits |= cp;
 727             putChar(result, i, cp);
 728         }
 729         if (bits > 0xFF) {
 730             return new String(result, UTF16);
 731         } else {
 732             return newString(result, 0, len);
 733         }
 734     }
 735 
 736     private static String toUpperCaseEx(String str, byte[] value,
 737                                         byte[] result, int first,
 738                                         Locale locale, boolean localeDependent)
 739     {
 740         int resultOffset = first;
 741         int length = value.length >> 1;
 742         int srcCount;
 743         for (int i = first; i < length; i += srcCount) {
 744             int srcChar = getChar(value, i);
 745             int upperChar;
 746             char[] upperCharArray;
 747             srcCount = 1;
 748             if (Character.isSurrogate((char)srcChar)) {
 749                 srcChar = codePointAt(value, i, length);
 750                 srcCount = Character.charCount(srcChar);
 751             }
 752             if (localeDependent) {
 753                 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
 754             } else {
 755                 upperChar = Character.toUpperCaseEx(srcChar);
 756             }
 757             if (Character.isBmpCodePoint(upperChar)) {
 758                 putChar(result, resultOffset++, upperChar);
 759             } else {
 760                 if (upperChar == Character.ERROR) {
 761                     if (localeDependent) {
 762                         upperCharArray =
 763                             ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
 764                     } else {
 765                         upperCharArray = Character.toUpperCaseCharArray(srcChar);
 766                     }
 767                 } else {
 768                     upperCharArray = Character.toChars(upperChar);
 769                 }
 770                 /* Grow result if needed */
 771                 int mapLen = upperCharArray.length;
 772                 if (mapLen > srcCount) {
 773                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 774                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 775                     result = result2;
 776                  }
 777                  for (int x = 0; x < mapLen; ++x) {
 778                     putChar(result, resultOffset++, upperCharArray[x]);
 779                  }
 780             }
 781         }
 782         return newString(result, 0, resultOffset);
 783     }
 784 
 785     public static String trim(byte[] value) {
 786         int length = value.length >> 1;
 787         int len = length;
 788         int st = 0;
 789         while (st < len && getChar(value, st) <= ' ') {
 790             st++;
 791         }
 792         while (st < len && getChar(value, len - 1) <= ' ') {
 793             len--;
 794         }
 795         return ((st > 0) || (len < length )) ?
 796             new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) :
 797             null;
 798     }
 799 
 800     public static void putChars(byte[] val, int index, char[] str, int off, int end) {
 801         while (off < end) {
 802             putChar(val, index++, str[off++]);
 803         }
 804     }
 805 
 806     public static String newString(byte[] val, int index, int len) {
 807         if (String.COMPACT_STRINGS) {
 808             byte[] buf = compress(val, index, len);
 809             if (buf != null) {
 810                 return new String(buf, LATIN1);
 811             }
 812         }
 813         int last = index + len;
 814         return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
 815     }
 816 
 817     public static void fillNull(byte[] val, int index, int end) {
 818         Arrays.fill(val, index << 1, end << 1, (byte)0);
 819     }
 820 
 821     static class CharsSpliterator implements Spliterator.OfInt {
 822         private final byte[] array;
 823         private int index;        // current index, modified on advance/split
 824         private final int fence;  // one past last index
 825         private final int cs;
 826 
 827         CharsSpliterator(byte[] array, int acs) {
 828             this(array, 0, array.length >> 1, acs);
 829         }
 830 
 831         CharsSpliterator(byte[] array, int origin, int fence, int acs) {
 832             this.array = array;
 833             this.index = origin;
 834             this.fence = fence;
 835             this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
 836                       | Spliterator.SUBSIZED;
 837         }
 838 
 839         @Override
 840         public OfInt trySplit() {
 841             int lo = index, mid = (lo + fence) >>> 1;
 842             return (lo >= mid)
 843                    ? null
 844                    : new CharsSpliterator(array, lo, index = mid, cs);
 845         }
 846 
 847         @Override
 848         public void forEachRemaining(IntConsumer action) {
 849             byte[] a; int i, hi; // hoist accesses and checks from loop
 850             if (action == null)
 851                 throw new NullPointerException();
 852             if (((a = array).length >> 1) >= (hi = fence) &&
 853                 (i = index) >= 0 && i < (index = hi)) {
 854                 do {
 855                     action.accept(charAt(a, i));
 856                 } while (++i < hi);
 857             }
 858         }
 859 
 860         @Override
 861         public boolean tryAdvance(IntConsumer action) {
 862             if (action == null)
 863                 throw new NullPointerException();
 864             int i = index;
 865             if (i >= 0 && i < fence) {
 866                 action.accept(charAt(array, i));
 867                 index++;
 868                 return true;
 869             }
 870             return false;
 871         }
 872 
 873         @Override
 874         public long estimateSize() { return (long)(fence - index); }
 875 
 876         @Override
 877         public int characteristics() {
 878             return cs;
 879         }
 880     }
 881 
 882     static class CodePointsSpliterator implements Spliterator.OfInt {
 883         private final byte[] array;
 884         private int index;        // current index, modified on advance/split
 885         private final int fence;  // one past last index
 886         private final int cs;
 887 
 888         CodePointsSpliterator(byte[] array, int acs) {
 889             this(array, 0, array.length >> 1, acs);
 890         }
 891 
 892         CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
 893             this.array = array;
 894             this.index = origin;
 895             this.fence = fence;
 896             this.cs = acs | Spliterator.ORDERED;
 897         }
 898 
 899         @Override
 900         public OfInt trySplit() {
 901             int lo = index, mid = (lo + fence) >>> 1;
 902             if (lo >= mid)
 903                 return null;
 904 
 905             int midOneLess;
 906             // If the mid-point intersects a surrogate pair
 907             if (Character.isLowSurrogate(charAt(array, mid)) &&
 908                 Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) {
 909                 // If there is only one pair it cannot be split
 910                 if (lo >= midOneLess)
 911                     return null;
 912                 // Shift the mid-point to align with the surrogate pair
 913                 return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
 914             }
 915             return new CodePointsSpliterator(array, lo, index = mid, cs);
 916         }
 917 
 918         @Override
 919         public void forEachRemaining(IntConsumer action) {
 920             byte[] a; int i, hi; // hoist accesses and checks from loop
 921             if (action == null)
 922                 throw new NullPointerException();
 923             if (((a = array).length >> 1) >= (hi = fence) &&
 924                 (i = index) >= 0 && i < (index = hi)) {
 925                 do {
 926                     i = advance(a, i, hi, action);
 927                 } while (i < hi);
 928             }
 929         }
 930 
 931         @Override
 932         public boolean tryAdvance(IntConsumer action) {
 933             if (action == null)
 934                 throw new NullPointerException();
 935             if (index >= 0 && index < fence) {
 936                 index = advance(array, index, fence, action);
 937                 return true;
 938             }
 939             return false;
 940         }
 941 
 942         // Advance one code point from the index, i, and return the next
 943         // index to advance from
 944         private static int advance(byte[] a, int i, int hi, IntConsumer action) {
 945             char c1 = charAt(a, i++);
 946             int cp = c1;
 947             if (Character.isHighSurrogate(c1) && i < hi) {
 948                 char c2 = charAt(a, i);
 949                 if (Character.isLowSurrogate(c2)) {
 950                     i++;
 951                     cp = Character.toCodePoint(c1, c2);
 952                 }
 953             }
 954             action.accept(cp);
 955             return i;
 956         }
 957 
 958         @Override
 959         public long estimateSize() { return (long)(fence - index); }
 960 
 961         @Override
 962         public int characteristics() {
 963             return cs;
 964         }
 965     }
 966 
 967     ////////////////////////////////////////////////////////////////
 968 
 969     public static void putCharSB(byte[] val, int index, int c) {
 970         checkIndex(index, val.length >> 1);
 971         putChar(val, index, c);
 972     }
 973 
 974     public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
 975         checkBoundsOffCount(index, index + end - off, val.length >> 1);
 976         putChars(val, index, ca, off, end);
 977     }
 978 
 979     public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
 980         checkBoundsOffCount(index, end - off, val.length >> 1);
 981         for (int i = off; i < end; i++) {
 982             putChar(val, index++, s.charAt(i));
 983         }
 984     }
 985 
 986     public static int codePointAtSB(byte[] val, int index, int end) {
 987         checkOffset(end, val.length >> 1);
 988         return codePointAt(val, index, end);
 989     }
 990 
 991     public static int codePointBeforeSB(byte[] val, int index) {
 992         checkOffset(index, val.length >> 1);
 993         return codePointBefore(val, index);
 994     }
 995 
 996     public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
 997         checkBoundsBeginEnd(beginIndex, endIndex, val.length >> 1);
 998         return codePointCount(val, beginIndex, endIndex);
 999     }
1000 
1001     ////////////////////////////////////////////////////////////////
1002 
1003     private static native boolean isBigEndian();
1004 
1005     static final int HI_BYTE_SHIFT;
1006     static final int LO_BYTE_SHIFT;
1007     static {
1008         if (isBigEndian()) {
1009             HI_BYTE_SHIFT = 8;
1010             LO_BYTE_SHIFT = 0;
1011         } else {
1012             HI_BYTE_SHIFT = 0;
1013             LO_BYTE_SHIFT = 8;
1014         }
1015     }
1016 
1017     static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
1018 }