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