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 compareToCI(byte[] value, byte[] other) {
 274         int len1 = length(value);
 275         int len2 = length(other);
 276         int lim = Math.min(len1, len2);
 277         for (int k = 0; k < lim; k++) {
 278             char c1 = getChar(value, k);
 279             char c2 = getChar(other, k);
 280             if (c1 != c2) {
 281                 c1 = Character.toUpperCase(c1);
 282                 c2 = Character.toUpperCase(c2);
 283                 if (c1 != c2) {
 284                     c1 = Character.toLowerCase(c1);
 285                     c2 = Character.toLowerCase(c2);
 286                     if (c1 != c2) {
 287                         return c1 - c2;
 288                     }
 289                 }
 290             }
 291         }
 292         return len1 - len2;
 293     }
 294 
 295     /**
 296      * hashCode consistent with {@link #compareToCI}
 297      */
 298     public static int hashCodeCI(byte[] value) {
 299         int len = length(value);
 300         int h = 0;
 301         for (int k = 0; k < len; k++) {
 302             char cu = (char) CharacterDataLatin1.instance.toUpperCase(getChar(value, k));
 303             char cl = (char) CharacterDataLatin1.instance.toLowerCase(cu);
 304             h = 31 * h + cl;
 305         }
 306         return h;
 307     }
 308 
 309     public static int compareToCI_Latin1(byte[] value, byte[] other) {
 310         int len1 = length(value);
 311         int len2 = StringLatin1.length(other);
 312         int lim = Math.min(len1, len2);
 313         for (int k = 0; k < lim; k++) {
 314             char c1 = getChar(value, k);
 315             char c2 = StringLatin1.getChar(other, k);
 316             if (c1 != c2) {
 317                 c1 = Character.toUpperCase(c1);
 318                 c2 = Character.toUpperCase(c2);
 319                 if (c1 != c2) {
 320                     c1 = Character.toLowerCase(c1);
 321                     c2 = Character.toLowerCase(c2);
 322                     if (c1 != c2) {
 323                         return c1 - c2;
 324                     }
 325                 }
 326             }
 327         }
 328         return len1 - len2;
 329     }
 330 
 331     public static int hashCode(byte[] value) {
 332         int h = 0;
 333         int length = value.length >> 1;
 334         for (int i = 0; i < length; i++) {
 335             h = 31 * h + getChar(value, i);
 336         }
 337         return h;
 338     }
 339 
 340     public static int indexOf(byte[] value, int ch, int fromIndex) {
 341         int max = value.length >> 1;
 342         if (fromIndex < 0) {
 343             fromIndex = 0;
 344         } else if (fromIndex >= max) {
 345             // Note: fromIndex might be near -1>>>1.
 346             return -1;
 347         }
 348         if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
 349             // handle most cases here (ch is a BMP code point or a
 350             // negative value (invalid code point))
 351             return indexOfChar(value, ch, fromIndex, max);
 352         } else {
 353             return indexOfSupplementary(value, ch, fromIndex, max);
 354         }
 355     }
 356 
 357     @HotSpotIntrinsicCandidate
 358     public static int indexOf(byte[] value, byte[] str) {
 359         if (str.length == 0) {
 360             return 0;
 361         }
 362         if (value.length == 0) {
 363             return -1;
 364         }
 365         return indexOf(value, length(value), str, length(str), 0);
 366     }
 367 
 368     @HotSpotIntrinsicCandidate
 369     public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
 370         char first = getChar(str, 0);
 371         int max = (valueCount - strCount);
 372         for (int i = fromIndex; i <= max; i++) {
 373             // Look for first character.
 374             if (getChar(value, i) != first) {
 375                 while (++i <= max && getChar(value, i) != first);
 376             }
 377             // Found first character, now look at the rest of value
 378             if (i <= max) {
 379                 int j = i + 1;
 380                 int end = j + strCount - 1;
 381                 for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++);
 382                 if (j == end) {
 383                     // Found whole string.
 384                     return i;
 385                 }
 386             }
 387         }
 388         return -1;
 389     }
 390 
 391     /**
 392      * Handles indexOf Latin1 substring in UTF16 string.
 393      */
 394     @HotSpotIntrinsicCandidate
 395     public static int indexOfLatin1(byte[] value, byte[] str) {
 396         if (str.length == 0) {
 397             return 0;
 398         }
 399         if (value.length == 0) {
 400             return -1;
 401         }
 402         return indexOfLatin1(value, length(value), str, str.length, 0);
 403     }
 404 
 405     @HotSpotIntrinsicCandidate
 406     public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
 407         char first = (char)(tgt[0] & 0xff);
 408         int max = (srcCount - tgtCount);
 409         for (int i = fromIndex; i <= max; i++) {
 410             // Look for first character.
 411             if (getChar(src, i) != first) {
 412                 while (++i <= max && getChar(src, i) != first);
 413             }
 414             // Found first character, now look at the rest of v2
 415             if (i <= max) {
 416                 int j = i + 1;
 417                 int end = j + tgtCount - 1;
 418                 for (int k = 1;
 419                      j < end && getChar(src, j) == (tgt[k] & 0xff);
 420                      j++, k++);
 421                 if (j == end) {
 422                     // Found whole string.
 423                     return i;
 424                 }
 425             }
 426         }
 427         return -1;
 428     }
 429 
 430     @HotSpotIntrinsicCandidate
 431     private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) {
 432         for (int i = fromIndex; i < max; i++) {
 433             if (getChar(value, i) == ch) {
 434                 return i;
 435             }
 436         }
 437         return -1;
 438     }
 439 
 440     /**
 441      * Handles (rare) calls of indexOf with a supplementary character.
 442      */
 443     private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) {
 444         if (Character.isValidCodePoint(ch)) {
 445             final char hi = Character.highSurrogate(ch);
 446             final char lo = Character.lowSurrogate(ch);
 447             for (int i = fromIndex; i < max - 1; i++) {
 448                 if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) {
 449                     return i;
 450                 }
 451             }
 452         }
 453         return -1;
 454     }
 455 
 456     public static int lastIndexOf(byte[] src, int srcCount,
 457                                   byte[] tgt, int tgtCount, int fromIndex) {
 458         int min = tgtCount - 1;
 459         int i = min + fromIndex;
 460         int strLastIndex = tgtCount - 1;
 461         char strLastChar = getChar(tgt, strLastIndex);
 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         int last = toffset + len;
 582         while (toffset < last) {
 583             char c1 = getChar(value, toffset++);
 584             char c2 = (char)(other[ooffset++] & 0xff);
 585             if (c1 == c2) {
 586                 continue;
 587             }
 588             char u1 = Character.toUpperCase(c1);
 589             char u2 = Character.toUpperCase(c2);
 590             if (u1 == u2) {
 591                 continue;
 592             }
 593             if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
 594                 continue;
 595             }
 596             return false;
 597         }
 598         return true;
 599     }
 600 
 601     public static String toLowerCase(String str, byte[] value, Locale locale) {
 602         if (locale == null) {
 603             throw new NullPointerException();
 604         }
 605         int first;
 606         boolean hasSurr = false;
 607         final int len = value.length >> 1;
 608 
 609         // Now check if there are any characters that need to be changed, or are surrogate
 610         for (first = 0 ; first < len; first++) {
 611             int cp = (int)getChar(value, first);
 612             if (Character.isSurrogate((char)cp)) {
 613                 hasSurr = true;
 614                 break;
 615             }
 616             if (cp != Character.toLowerCase(cp)) {  // no need to check Character.ERROR
 617                 break;
 618             }
 619         }
 620         if (first == len)
 621             return str;
 622         byte[] result = new byte[value.length];
 623         System.arraycopy(value, 0, result, 0, first << 1);  // Just copy the first few
 624                                                             // lowerCase characters.
 625         String lang = locale.getLanguage();
 626         if (lang == "tr" || lang == "az" || lang == "lt") {
 627             return toLowerCaseEx(str, value, result, first, locale, true);
 628         }
 629         if (hasSurr) {
 630             return toLowerCaseEx(str, value, result, first, locale, false);
 631         }
 632         int bits = 0;
 633         for (int i = first; i < len; i++) {
 634             int cp = (int)getChar(value, i);
 635             if (cp == '\u03A3' ||                       // GREEK CAPITAL LETTER SIGMA
 636                 Character.isSurrogate((char)cp)) {
 637                 return toLowerCaseEx(str, value, result, i, locale, false);
 638             }
 639             if (cp == '\u0130') {                       // LATIN CAPITAL LETTER I WITH DOT ABOVE
 640                 return toLowerCaseEx(str, value, result, i, locale, true);
 641             }
 642             cp = Character.toLowerCase(cp);
 643             if (!Character.isBmpCodePoint(cp)) {
 644                 return toLowerCaseEx(str, value, result, i, locale, false);
 645             }
 646             bits |= cp;
 647             putChar(result, i, cp);
 648         }
 649         if (bits > 0xFF) {
 650             return new String(result, UTF16);
 651         } else {
 652             return newString(result, 0, len);
 653         }
 654     }
 655 
 656     private static String toLowerCaseEx(String str, byte[] value,
 657                                         byte[] result, int first, Locale locale,
 658                                         boolean localeDependent) {
 659         int resultOffset = first;
 660         int length = value.length >> 1;
 661         int srcCount;
 662         for (int i = first; i < length; i += srcCount) {
 663             int srcChar = getChar(value, i);
 664             int lowerChar;
 665             char[] lowerCharArray;
 666             srcCount = 1;
 667             if (Character.isSurrogate((char)srcChar)) {
 668                 srcChar = codePointAt(value, i, length);
 669                 srcCount = Character.charCount(srcChar);
 670             }
 671             if (localeDependent ||
 672                 srcChar == '\u03A3' ||  // GREEK CAPITAL LETTER SIGMA
 673                 srcChar == '\u0130') {  // LATIN CAPITAL LETTER I WITH DOT ABOVE
 674                 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
 675             } else {
 676                 lowerChar = Character.toLowerCase(srcChar);
 677             }
 678             if (Character.isBmpCodePoint(lowerChar)) {    // Character.ERROR is not a bmp
 679                 putChar(result, resultOffset++, lowerChar);
 680             } else {
 681                 if (lowerChar == Character.ERROR) {
 682                     lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
 683                 } else {
 684                     lowerCharArray = Character.toChars(lowerChar);
 685                 }
 686                 /* Grow result if needed */
 687                 int mapLen = lowerCharArray.length;
 688                 if (mapLen > srcCount) {
 689                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 690                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 691                     result = result2;
 692                 }
 693                 for (int x = 0; x < mapLen; ++x) {
 694                     putChar(result, resultOffset++, lowerCharArray[x]);
 695                 }
 696             }
 697         }
 698         return newString(result, 0, resultOffset);
 699     }
 700 
 701     public static String toUpperCase(String str, byte[] value, Locale locale) {
 702         if (locale == null) {
 703             throw new NullPointerException();
 704         }
 705         int first;
 706         boolean hasSurr = false;
 707         final int len = value.length >> 1;
 708 
 709         // Now check if there are any characters that need to be changed, or are surrogate
 710         for (first = 0 ; first < len; first++) {
 711             int cp = (int)getChar(value, first);
 712             if (Character.isSurrogate((char)cp)) {
 713                 hasSurr = true;
 714                 break;
 715             }
 716             if (cp != Character.toUpperCaseEx(cp)) {   // no need to check Character.ERROR
 717                 break;
 718             }
 719         }
 720         if (first == len) {
 721             return str;
 722         }
 723         byte[] result = new byte[value.length];
 724         System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
 725                                                            // upperCase characters.
 726         String lang = locale.getLanguage();
 727         if (lang == "tr" || lang == "az" || lang == "lt") {
 728             return toUpperCaseEx(str, value, result, first, locale, true);
 729         }
 730         if (hasSurr) {
 731             return toUpperCaseEx(str, value, result, first, locale, false);
 732         }
 733         int bits = 0;
 734         for (int i = first; i < len; i++) {
 735             int cp = (int)getChar(value, i);
 736             if (Character.isSurrogate((char)cp)) {
 737                 return toUpperCaseEx(str, value, result, i, locale, false);
 738             }
 739             cp = Character.toUpperCaseEx(cp);
 740             if (!Character.isBmpCodePoint(cp)) {    // Character.ERROR is not bmp
 741                 return toUpperCaseEx(str, value, result, i, locale, false);
 742             }
 743             bits |= cp;
 744             putChar(result, i, cp);
 745         }
 746         if (bits > 0xFF) {
 747             return new String(result, UTF16);
 748         } else {
 749             return newString(result, 0, len);
 750         }
 751     }
 752 
 753     private static String toUpperCaseEx(String str, byte[] value,
 754                                         byte[] result, int first,
 755                                         Locale locale, boolean localeDependent)
 756     {
 757         int resultOffset = first;
 758         int length = value.length >> 1;
 759         int srcCount;
 760         for (int i = first; i < length; i += srcCount) {
 761             int srcChar = getChar(value, i);
 762             int upperChar;
 763             char[] upperCharArray;
 764             srcCount = 1;
 765             if (Character.isSurrogate((char)srcChar)) {
 766                 srcChar = codePointAt(value, i, length);
 767                 srcCount = Character.charCount(srcChar);
 768             }
 769             if (localeDependent) {
 770                 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
 771             } else {
 772                 upperChar = Character.toUpperCaseEx(srcChar);
 773             }
 774             if (Character.isBmpCodePoint(upperChar)) {
 775                 putChar(result, resultOffset++, upperChar);
 776             } else {
 777                 if (upperChar == Character.ERROR) {
 778                     if (localeDependent) {
 779                         upperCharArray =
 780                             ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
 781                     } else {
 782                         upperCharArray = Character.toUpperCaseCharArray(srcChar);
 783                     }
 784                 } else {
 785                     upperCharArray = Character.toChars(upperChar);
 786                 }
 787                 /* Grow result if needed */
 788                 int mapLen = upperCharArray.length;
 789                 if (mapLen > srcCount) {
 790                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 791                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 792                     result = result2;
 793                  }
 794                  for (int x = 0; x < mapLen; ++x) {
 795                     putChar(result, resultOffset++, upperCharArray[x]);
 796                  }
 797             }
 798         }
 799         return newString(result, 0, resultOffset);
 800     }
 801 
 802     public static String trim(byte[] value) {
 803         int length = value.length >> 1;
 804         int len = length;
 805         int st = 0;
 806         while (st < len && getChar(value, st) <= ' ') {
 807             st++;
 808         }
 809         while (st < len && getChar(value, len - 1) <= ' ') {
 810             len--;
 811         }
 812         return ((st > 0) || (len < length )) ?
 813             new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) :
 814             null;
 815     }
 816 
 817     public static void putChars(byte[] val, int index, char[] str, int off, int end) {
 818         while (off < end) {
 819             putChar(val, index++, str[off++]);
 820         }
 821     }
 822 
 823     public static String newString(byte[] val, int index, int len) {
 824         if (String.COMPACT_STRINGS) {
 825             byte[] buf = compress(val, index, len);
 826             if (buf != null) {
 827                 return new String(buf, LATIN1);
 828             }
 829         }
 830         int last = index + len;
 831         return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
 832     }
 833 
 834     public static void fillNull(byte[] val, int index, int end) {
 835         Arrays.fill(val, index << 1, end << 1, (byte)0);
 836     }
 837 
 838     static class CharsSpliterator implements Spliterator.OfInt {
 839         private final byte[] array;
 840         private int index;        // current index, modified on advance/split
 841         private final int fence;  // one past last index
 842         private final int cs;
 843 
 844         CharsSpliterator(byte[] array, int acs) {
 845             this(array, 0, array.length >> 1, acs);
 846         }
 847 
 848         CharsSpliterator(byte[] array, int origin, int fence, int acs) {
 849             this.array = array;
 850             this.index = origin;
 851             this.fence = fence;
 852             this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
 853                       | Spliterator.SUBSIZED;
 854         }
 855 
 856         @Override
 857         public OfInt trySplit() {
 858             int lo = index, mid = (lo + fence) >>> 1;
 859             return (lo >= mid)
 860                    ? null
 861                    : new CharsSpliterator(array, lo, index = mid, cs);
 862         }
 863 
 864         @Override
 865         public void forEachRemaining(IntConsumer action) {
 866             byte[] a; int i, hi; // hoist accesses and checks from loop
 867             if (action == null)
 868                 throw new NullPointerException();
 869             if (((a = array).length >> 1) >= (hi = fence) &&
 870                 (i = index) >= 0 && i < (index = hi)) {
 871                 do { action.accept(getChar(a, i)); } while (++i < hi);
 872             }
 873         }
 874 
 875         @Override
 876         public boolean tryAdvance(IntConsumer action) {
 877             if (action == null)
 878                 throw new NullPointerException();
 879             if (index >= 0 && index < fence) {
 880                 action.accept(getChar(array, index++));
 881                 return true;
 882             }
 883             return false;
 884         }
 885 
 886         @Override
 887         public long estimateSize() { return (long)(fence - index); }
 888 
 889         @Override
 890         public int characteristics() {
 891             return cs;
 892         }
 893     }
 894 
 895     static class CodePointsSpliterator implements Spliterator.OfInt {
 896         private final byte[] array;
 897         private int index;        // current index, modified on advance/split
 898         private final int fence;  // one past last index
 899         private final int cs;
 900 
 901         CodePointsSpliterator(byte[] array, int acs) {
 902             this(array, 0, array.length >> 1, acs);
 903         }
 904 
 905         CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
 906             this.array = array;
 907             this.index = origin;
 908             this.fence = fence;
 909             this.cs = acs | Spliterator.ORDERED;
 910         }
 911 
 912         @Override
 913         public OfInt trySplit() {
 914             int lo = index, mid = (lo + fence) >>> 1;
 915             if (lo >= mid)
 916                 return null;
 917 
 918             int midOneLess;
 919             // If the mid-point intersects a surrogate pair
 920             if (Character.isLowSurrogate(getChar(array, mid)) &&
 921                 Character.isHighSurrogate(getChar(array, midOneLess = (mid -1)))) {
 922                 // If there is only one pair it cannot be split
 923                 if (lo >= midOneLess)
 924                     return null;
 925                 // Shift the mid-point to align with the surrogate pair
 926                 return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
 927             }
 928             return new CodePointsSpliterator(array, lo, index = mid, cs);
 929         }
 930 
 931         @Override
 932         public void forEachRemaining(IntConsumer action) {
 933             byte[] a; int i, hi; // hoist accesses and checks from loop
 934             if (action == null)
 935                 throw new NullPointerException();
 936             if (((a = array).length >> 1) >= (hi = fence) &&
 937                 (i = index) >= 0 && i < (index = hi)) {
 938                 do {
 939                     i = advance(a, i, hi, action);
 940                 } while (i < hi);
 941             }
 942         }
 943 
 944         @Override
 945         public boolean tryAdvance(IntConsumer action) {
 946             if (action == null)
 947                 throw new NullPointerException();
 948             if (index >= 0 && index < fence) {
 949                 index = advance(array, index, fence, action);
 950                 return true;
 951             }
 952             return false;
 953         }
 954 
 955         // Advance one code point from the index, i, and return the next
 956         // index to advance from
 957         private static int advance(byte[] a, int i, int hi, IntConsumer action) {
 958             char c1 = getChar(a, i++);
 959             int cp = c1;
 960             if (Character.isHighSurrogate(c1) && i < hi) {
 961                 char c2 = getChar(a, i);
 962                 if (Character.isLowSurrogate(c2)) {
 963                     i++;
 964                     cp = Character.toCodePoint(c1, c2);
 965                 }
 966             }
 967             action.accept(cp);
 968             return i;
 969         }
 970 
 971         @Override
 972         public long estimateSize() { return (long)(fence - index); }
 973 
 974         @Override
 975         public int characteristics() {
 976             return cs;
 977         }
 978     }
 979 
 980     ////////////////////////////////////////////////////////////////
 981 
 982     public static void putCharSB(byte[] val, int index, int c) {
 983         checkIndex(index, val.length >> 1);
 984         putChar(val, index, c);
 985     }
 986 
 987     public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
 988         checkOffset(index + end - off, val.length >> 1);
 989         putChars(val, index, ca, off, end);
 990     }
 991 
 992     public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
 993         checkOffset(index + end - off, val.length >> 1);
 994         for (int i = off; i < end; i++) {
 995             putChar(val, index++, s.charAt(i));
 996         }
 997     }
 998 
 999     public static int codePointAtSB(byte[] val, int index, int end) {
1000         checkOffset(end, val.length >> 1);
1001         return codePointAt(val, index, end);
1002     }
1003 
1004     public static int codePointBeforeSB(byte[] val, int index) {
1005         checkOffset(index, val.length >> 1);
1006         return codePointBefore(val, index);
1007     }
1008 
1009     public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
1010         checkOffset(endIndex, val.length >> 1);
1011         return codePointCount(val, beginIndex, endIndex);
1012     }
1013 
1014     ////////////////////////////////////////////////////////////////
1015 
1016     private static native boolean isBigEndian();
1017 
1018     static final int HI_BYTE_SHIFT;
1019     static final int LO_BYTE_SHIFT;
1020     static {
1021         if (isBigEndian()) {
1022             HI_BYTE_SHIFT = 8;
1023             LO_BYTE_SHIFT = 0;
1024         } else {
1025             HI_BYTE_SHIFT = 0;
1026             LO_BYTE_SHIFT = 8;
1027         }
1028     }
1029 
1030     static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
1031 }