1 /*
   2  * Copyright (c) 2015, 2018, 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.Consumer;
  32 import java.util.function.IntConsumer;
  33 import java.util.stream.Stream;
  34 import java.util.stream.StreamSupport;
  35 import jdk.internal.HotSpotIntrinsicCandidate;
  36 import jdk.internal.util.ArraysSupport;
  37 import jdk.internal.vm.annotation.ForceInline;
  38 import jdk.internal.vm.annotation.DontInline;
  39 
  40 import static java.lang.String.UTF16;
  41 import static java.lang.String.LATIN1;
  42 
  43 final class StringUTF16 {
  44 
  45     public static byte[] newBytesFor(int len) {
  46         if (len < 0) {
  47             throw new NegativeArraySizeException();
  48         }
  49         if (len > MAX_LENGTH) {
  50             throw new OutOfMemoryError("UTF16 String size is " + len +
  51                                        ", should be less than " + MAX_LENGTH);
  52         }
  53         return new byte[len << 1];
  54     }
  55 
  56     @HotSpotIntrinsicCandidate
  57     // intrinsic performs no bounds checks
  58     static void putChar(byte[] val, int index, int c) {
  59         assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
  60         index <<= 1;
  61         val[index++] = (byte)(c >> HI_BYTE_SHIFT);
  62         val[index]   = (byte)(c >> LO_BYTE_SHIFT);
  63     }
  64 
  65     @HotSpotIntrinsicCandidate
  66     // intrinsic performs no bounds checks
  67     static char getChar(byte[] val, int index) {
  68         assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
  69         index <<= 1;
  70         return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
  71                       ((val[index]   & 0xff) << LO_BYTE_SHIFT));
  72     }
  73 
  74     public static int length(byte[] value) {
  75         return value.length >> 1;
  76     }
  77 
  78     private static int codePointAt(byte[] value, int index, int end, boolean checked) {
  79         assert index < end;
  80         if (checked) {
  81             checkIndex(index, value);
  82         }
  83         char c1 = getChar(value, index);
  84         if (Character.isHighSurrogate(c1) && ++index < end) {
  85             if (checked) {
  86                 checkIndex(index, value);
  87             }
  88             char c2 = getChar(value, index);
  89             if (Character.isLowSurrogate(c2)) {
  90                return Character.toCodePoint(c1, c2);
  91             }
  92         }
  93         return c1;
  94     }
  95 
  96     public static int codePointAt(byte[] value, int index, int end) {
  97        return codePointAt(value, index, end, false /* unchecked */);
  98     }
  99 
 100     private static int codePointBefore(byte[] value, int index, boolean checked) {
 101         --index;
 102         if (checked) {
 103             checkIndex(index, value);
 104         }
 105         char c2 = getChar(value, index);
 106         if (Character.isLowSurrogate(c2) && index > 0) {
 107             --index;
 108             if (checked) {
 109                 checkIndex(index, value);
 110             }
 111             char c1 = getChar(value, index);
 112             if (Character.isHighSurrogate(c1)) {
 113                return Character.toCodePoint(c1, c2);
 114             }
 115         }
 116         return c2;
 117     }
 118 
 119     public static int codePointBefore(byte[] value, int index) {
 120         return codePointBefore(value, index, false /* unchecked */);
 121     }
 122 
 123     private static int codePointCount(byte[] value, int beginIndex, int endIndex, boolean checked) {
 124         assert beginIndex <= endIndex;
 125         int count = endIndex - beginIndex;
 126         int i = beginIndex;
 127         if (checked && i < endIndex) {
 128             checkBoundsBeginEnd(i, endIndex, value);
 129         }
 130         for (; i < endIndex - 1; ) {
 131             if (Character.isHighSurrogate(getChar(value, i++)) &&
 132                 Character.isLowSurrogate(getChar(value, i))) {
 133                 count--;
 134                 i++;
 135             }
 136         }
 137         return count;
 138     }
 139 
 140     public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
 141         return codePointCount(value, beginIndex, endIndex, false /* unchecked */);
 142     }
 143 
 144     public static char[] toChars(byte[] value) {
 145         char[] dst = new char[value.length >> 1];
 146         getChars(value, 0, dst.length, dst, 0);
 147         return dst;
 148     }
 149 
 150     @HotSpotIntrinsicCandidate
 151     public static byte[] toBytes(char[] value, int off, int len) {
 152         byte[] val = newBytesFor(len);
 153         for (int i = 0; i < len; i++) {
 154             putChar(val, i, value[off]);
 155             off++;
 156         }
 157         return val;
 158     }
 159 
 160     public static byte[] compress(char[] val, int off, int len) {
 161         byte[] ret = new byte[len];
 162         if (compress(val, off, ret, 0, len) == len) {
 163             return ret;
 164         }
 165         return null;
 166     }
 167 
 168     public static byte[] compress(byte[] val, int off, int len) {
 169         byte[] ret = new byte[len];
 170         if (compress(val, off, ret, 0, len) == len) {
 171             return ret;
 172         }
 173         return null;
 174     }
 175 
 176     // compressedCopy char[] -> byte[]
 177     @HotSpotIntrinsicCandidate
 178     public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
 179         for (int i = 0; i < len; i++) {
 180             char c = src[srcOff];
 181             if (c > 0xFF) {
 182                 len = 0;
 183                 break;
 184             }
 185             dst[dstOff] = (byte)c;
 186             srcOff++;
 187             dstOff++;
 188         }
 189         return len;
 190     }
 191 
 192     // compressedCopy byte[] -> byte[]
 193     @HotSpotIntrinsicCandidate
 194     public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
 195         // We need a range check here because 'getChar' has no checks
 196         checkBoundsOffCount(srcOff, len, src);
 197         for (int i = 0; i < len; i++) {
 198             char c = getChar(src, srcOff);
 199             if (c > 0xFF) {
 200                 len = 0;
 201                 break;
 202             }
 203             dst[dstOff] = (byte)c;
 204             srcOff++;
 205             dstOff++;
 206         }
 207         return len;
 208     }
 209 
 210     public static byte[] toBytes(int[] val, int index, int len) {
 211         final int end = index + len;
 212         // Pass 1: Compute precise size of char[]
 213         int n = len;
 214         for (int i = index; i < end; i++) {
 215             int cp = val[i];
 216             if (Character.isBmpCodePoint(cp))
 217                 continue;
 218             else if (Character.isValidCodePoint(cp))
 219                 n++;
 220             else throw new IllegalArgumentException(Integer.toString(cp));
 221         }
 222         // Pass 2: Allocate and fill in <high, low> pair
 223         byte[] buf = newBytesFor(n);
 224         for (int i = index, j = 0; i < end; i++, j++) {
 225             int cp = val[i];
 226             if (Character.isBmpCodePoint(cp)) {
 227                 putChar(buf, j, cp);
 228             } else {
 229                 putChar(buf, j++, Character.highSurrogate(cp));
 230                 putChar(buf, j, Character.lowSurrogate(cp));
 231             }
 232         }
 233         return buf;
 234     }
 235 
 236     public static byte[] toBytes(char c) {
 237         byte[] result = new byte[2];
 238         putChar(result, 0, c);
 239         return result;
 240     }
 241 
 242     static byte[] toBytesSupplementary(int cp) {
 243         byte[] result = new byte[4];
 244         putChar(result, 0, Character.highSurrogate(cp));
 245         putChar(result, 1, Character.lowSurrogate(cp));
 246         return result;
 247     }
 248 
 249     @HotSpotIntrinsicCandidate
 250     public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
 251         // We need a range check here because 'getChar' has no checks
 252         if (srcBegin < srcEnd) {
 253             checkBoundsOffCount(srcBegin, srcEnd - srcBegin, value);
 254         }
 255         for (int i = srcBegin; i < srcEnd; i++) {
 256             dst[dstBegin++] = getChar(value, i);
 257         }
 258     }
 259 
 260     /* @see java.lang.String.getBytes(int, int, byte[], int) */
 261     public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
 262         srcBegin <<= 1;
 263         srcEnd <<= 1;
 264         for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) {
 265             dst[dstBegin++] = value[i];
 266         }
 267     }
 268 
 269     @HotSpotIntrinsicCandidate
 270     public static boolean equals(byte[] value, byte[] other) {
 271         if (value.length == other.length) {
 272             int len = value.length >> 1;
 273             for (int i = 0; i < len; i++) {
 274                 if (getChar(value, i) != getChar(other, i)) {
 275                     return false;
 276                 }
 277             }
 278             return true;
 279         }
 280         return false;
 281     }
 282 
 283     @HotSpotIntrinsicCandidate
 284     public static int compareTo(byte[] value, byte[] other) {
 285         int len1 = length(value);
 286         int len2 = length(other);
 287         return compareValues(value, other, len1, len2);
 288     }
 289 
 290     /*
 291      * Checks the boundary and then compares the byte arrays.
 292      */
 293     public static int compareTo(byte[] value, byte[] other, int len1, int len2) {
 294         checkOffset(len1, value);
 295         checkOffset(len2, other);
 296 
 297         return compareValues(value, other, len1, len2);
 298     }
 299 
 300     private static int compareValues(byte[] value, byte[] other, int len1, int len2) {
 301         int lim = Math.min(len1, len2);
 302         for (int k = 0; k < lim; k++) {
 303             char c1 = getChar(value, k);
 304             char c2 = getChar(other, k);
 305             if (c1 != c2) {
 306                 return c1 - c2;
 307             }
 308         }
 309         return len1 - len2;
 310     }
 311 
 312     @HotSpotIntrinsicCandidate
 313     public static int compareToLatin1(byte[] value, byte[] other) {
 314         return -StringLatin1.compareToUTF16(other, value);
 315     }
 316 
 317     public static int compareToLatin1(byte[] value, byte[] other, int len1, int len2) {
 318         return -StringLatin1.compareToUTF16(other, value, len2, len1);
 319     }
 320 
 321     public static int compareToCI(byte[] value, byte[] other) {
 322         int len1 = length(value);
 323         int len2 = length(other);
 324         int lim = Math.min(len1, len2);
 325         for (int k = 0; k < lim; k++) {
 326             char c1 = getChar(value, k);
 327             char c2 = getChar(other, k);
 328             if (c1 != c2) {
 329                 c1 = Character.toUpperCase(c1);
 330                 c2 = Character.toUpperCase(c2);
 331                 if (c1 != c2) {
 332                     c1 = Character.toLowerCase(c1);
 333                     c2 = Character.toLowerCase(c2);
 334                     if (c1 != c2) {
 335                         return c1 - c2;
 336                     }
 337                 }
 338             }
 339         }
 340         return len1 - len2;
 341     }
 342 
 343     public static int compareToCI_Latin1(byte[] value, byte[] other) {
 344         return -StringLatin1.compareToCI_UTF16(other, value);
 345     }
 346 
 347     public static int hashCode(byte[] value) {
 348         int h = 0;
 349         int length = value.length >> 1;
 350         for (int i = 0; i < length; i++) {
 351             h = 31 * h + getChar(value, i);
 352         }
 353         return h;
 354     }
 355 
 356     public static int indexOf(byte[] value, int ch, int fromIndex) {
 357         int max = value.length >> 1;
 358         if (fromIndex < 0) {
 359             fromIndex = 0;
 360         } else if (fromIndex >= max) {
 361             // Note: fromIndex might be near -1>>>1.
 362             return -1;
 363         }
 364         if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
 365             // handle most cases here (ch is a BMP code point or a
 366             // negative value (invalid code point))
 367             return indexOfChar(value, ch, fromIndex, max);
 368         } else {
 369             return indexOfSupplementary(value, ch, fromIndex, max);
 370         }
 371     }
 372 
 373     @HotSpotIntrinsicCandidate
 374     public static int indexOf(byte[] value, byte[] str) {
 375         if (str.length == 0) {
 376             return 0;
 377         }
 378         if (value.length < str.length) {
 379             return -1;
 380         }
 381         return indexOfUnsafe(value, length(value), str, length(str), 0);
 382     }
 383 
 384     @HotSpotIntrinsicCandidate
 385     public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
 386         checkBoundsBeginEnd(fromIndex, valueCount, value);
 387         checkBoundsBeginEnd(0, strCount, str);
 388         return indexOfUnsafe(value, valueCount, str, strCount, fromIndex);
 389     }
 390 
 391 
 392     private static int indexOfUnsafe(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
 393         assert fromIndex >= 0;
 394         assert strCount > 0;
 395         assert strCount <= length(str);
 396         assert valueCount >= strCount;
 397         char first = getChar(str, 0);
 398         int max = (valueCount - strCount);
 399         for (int i = fromIndex; i <= max; i++) {
 400             // Look for first character.
 401             if (getChar(value, i) != first) {
 402                 while (++i <= max && getChar(value, i) != first);
 403             }
 404             // Found first character, now look at the rest of value
 405             if (i <= max) {
 406                 int j = i + 1;
 407                 int end = j + strCount - 1;
 408                 for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++);
 409                 if (j == end) {
 410                     // Found whole string.
 411                     return i;
 412                 }
 413             }
 414         }
 415         return -1;
 416     }
 417 
 418 
 419     /**
 420      * Handles indexOf Latin1 substring in UTF16 string.
 421      */
 422     @HotSpotIntrinsicCandidate
 423     public static int indexOfLatin1(byte[] value, byte[] str) {
 424         if (str.length == 0) {
 425             return 0;
 426         }
 427         if (length(value) < str.length) {
 428             return -1;
 429         }
 430         return indexOfLatin1Unsafe(value, length(value), str, str.length, 0);
 431     }
 432 
 433     @HotSpotIntrinsicCandidate
 434     public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
 435         checkBoundsBeginEnd(fromIndex, srcCount, src);
 436         String.checkBoundsBeginEnd(0, tgtCount, tgt.length);
 437         return indexOfLatin1Unsafe(src, srcCount, tgt, tgtCount, fromIndex);
 438     }
 439 
 440     public static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
 441         assert fromIndex >= 0;
 442         assert tgtCount > 0;
 443         assert tgtCount <= tgt.length;
 444         assert srcCount >= tgtCount;
 445         char first = (char)(tgt[0] & 0xff);
 446         int max = (srcCount - tgtCount);
 447         for (int i = fromIndex; i <= max; i++) {
 448             // Look for first character.
 449             if (getChar(src, i) != first) {
 450                 while (++i <= max && getChar(src, i) != first);
 451             }
 452             // Found first character, now look at the rest of v2
 453             if (i <= max) {
 454                 int j = i + 1;
 455                 int end = j + tgtCount - 1;
 456                 for (int k = 1;
 457                      j < end && getChar(src, j) == (tgt[k] & 0xff);
 458                      j++, k++);
 459                 if (j == end) {
 460                     // Found whole string.
 461                     return i;
 462                 }
 463             }
 464         }
 465         return -1;
 466     }
 467 
 468     @HotSpotIntrinsicCandidate
 469     private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) {
 470         checkBoundsBeginEnd(fromIndex, max, value);
 471         return indexOfCharUnsafe(value, ch, fromIndex, max);
 472     }
 473 
 474     private static int indexOfCharUnsafe(byte[] value, int ch, int fromIndex, int max) {
 475         for (int i = fromIndex; i < max; i++) {
 476             if (getChar(value, i) == ch) {
 477                 return i;
 478             }
 479         }
 480         return -1;
 481     }
 482 
 483     /**
 484      * Handles (rare) calls of indexOf with a supplementary character.
 485      */
 486     private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) {
 487         if (Character.isValidCodePoint(ch)) {
 488             final char hi = Character.highSurrogate(ch);
 489             final char lo = Character.lowSurrogate(ch);
 490             checkBoundsBeginEnd(fromIndex, max, value);
 491             for (int i = fromIndex; i < max - 1; i++) {
 492                 if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) {
 493                     return i;
 494                 }
 495             }
 496         }
 497         return -1;
 498     }
 499 
 500     // srcCoder == UTF16 && tgtCoder == UTF16
 501     public static int lastIndexOf(byte[] src, int srcCount,
 502                                   byte[] tgt, int tgtCount, int fromIndex) {
 503         assert fromIndex >= 0;
 504         assert tgtCount > 0;
 505         assert tgtCount <= length(tgt);
 506         int min = tgtCount - 1;
 507         int i = min + fromIndex;
 508         int strLastIndex = tgtCount - 1;
 509 
 510         checkIndex(strLastIndex, tgt);
 511         char strLastChar = getChar(tgt, strLastIndex);
 512 
 513         checkIndex(i, src);
 514 
 515     startSearchForLastChar:
 516         while (true) {
 517             while (i >= min && getChar(src, i) != strLastChar) {
 518                 i--;
 519             }
 520             if (i < min) {
 521                 return -1;
 522             }
 523             int j = i - 1;
 524             int start = j - strLastIndex;
 525             int k = strLastIndex - 1;
 526             while (j > start) {
 527                 if (getChar(src, j--) != getChar(tgt, k--)) {
 528                     i--;
 529                     continue startSearchForLastChar;
 530                 }
 531             }
 532             return start + 1;
 533         }
 534     }
 535 
 536     public static int lastIndexOf(byte[] value, int ch, int fromIndex) {
 537         if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
 538             // handle most cases here (ch is a BMP code point or a
 539             // negative value (invalid code point))
 540             int i = Math.min(fromIndex, (value.length >> 1) - 1);
 541             for (; i >= 0; i--) {
 542                 if (getChar(value, i) == ch) {
 543                     return i;
 544                 }
 545             }
 546             return -1;
 547         } else {
 548             return lastIndexOfSupplementary(value, ch, fromIndex);
 549         }
 550     }
 551 
 552     /**
 553      * Handles (rare) calls of lastIndexOf with a supplementary character.
 554      */
 555     private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) {
 556         if (Character.isValidCodePoint(ch)) {
 557             char hi = Character.highSurrogate(ch);
 558             char lo = Character.lowSurrogate(ch);
 559             int i = Math.min(fromIndex, (value.length >> 1) - 2);
 560             for (; i >= 0; i--) {
 561                 if (getChar(value, i) == hi && getChar(value, i + 1) == lo) {
 562                     return i;
 563                 }
 564             }
 565         }
 566         return -1;
 567     }
 568 
 569     public static String replace(byte[] value, char oldChar, char newChar) {
 570         int len = value.length >> 1;
 571         int i = -1;
 572         while (++i < len) {
 573             if (getChar(value, i) == oldChar) {
 574                 break;
 575             }
 576         }
 577         if (i < len) {
 578             byte[] buf = new byte[value.length];
 579             for (int j = 0; j < i; j++) {
 580                 putChar(buf, j, getChar(value, j)); // TBD:arraycopy?
 581             }
 582             while (i < len) {
 583                 char c = getChar(value, i);
 584                 putChar(buf, i, c == oldChar ? newChar : c);
 585                 i++;
 586             }
 587             // Check if we should try to compress to latin1
 588             if (String.COMPACT_STRINGS &&
 589                 !StringLatin1.canEncode(oldChar) &&
 590                 StringLatin1.canEncode(newChar)) {
 591                 byte[] val = compress(buf, 0, len);
 592                 if (val != null) {
 593                     return new String(val, LATIN1);
 594                 }
 595             }
 596             return new String(buf, UTF16);
 597         }
 598         return null;
 599     }
 600 
 601     public static String replace(byte[] value, int valLen, boolean valLat1,
 602                                  byte[] targ, int targLen, boolean targLat1,
 603                                  byte[] repl, int replLen, boolean replLat1)
 604     {
 605         assert targLen > 0;
 606         assert !valLat1 || !targLat1 || !replLat1;
 607 
 608         //  Possible combinations of the arguments/result encodings:
 609         //  +---+--------+--------+--------+-----------------------+
 610         //  | # | VALUE  | TARGET | REPL   | RESULT                |
 611         //  +===+========+========+========+=======================+
 612         //  | 1 | Latin1 | Latin1 |  UTF16 | null or UTF16         |
 613         //  +---+--------+--------+--------+-----------------------+
 614         //  | 2 | Latin1 |  UTF16 | Latin1 | null                  |
 615         //  +---+--------+--------+--------+-----------------------+
 616         //  | 3 | Latin1 |  UTF16 |  UTF16 | null                  |
 617         //  +---+--------+--------+--------+-----------------------+
 618         //  | 4 |  UTF16 | Latin1 | Latin1 | null or UTF16         |
 619         //  +---+--------+--------+--------+-----------------------+
 620         //  | 5 |  UTF16 | Latin1 |  UTF16 | null or UTF16         |
 621         //  +---+--------+--------+--------+-----------------------+
 622         //  | 6 |  UTF16 |  UTF16 | Latin1 | null, Latin1 or UTF16 |
 623         //  +---+--------+--------+--------+-----------------------+
 624         //  | 7 |  UTF16 |  UTF16 |  UTF16 | null or UTF16         |
 625         //  +---+--------+--------+--------+-----------------------+
 626 
 627         if (String.COMPACT_STRINGS && valLat1 && !targLat1) {
 628             // combinations 2 or 3
 629             return null; // for string to return this;
 630         }
 631 
 632         int i = (String.COMPACT_STRINGS && valLat1)
 633                         ? StringLatin1.indexOf(value, targ) :
 634                 (String.COMPACT_STRINGS && targLat1)
 635                         ? indexOfLatin1(value, targ)
 636                         : indexOf(value, targ);
 637         if (i < 0) {
 638             return null; // for string to return this;
 639         }
 640 
 641         // find and store indices of substrings to replace
 642         int j, p = 0;
 643         int[] pos = new int[16];
 644         pos[0] = i;
 645         i += targLen;
 646         while ((j = ((String.COMPACT_STRINGS && valLat1)
 647                             ? StringLatin1.indexOf(value, valLen, targ, targLen, i) :
 648                      (String.COMPACT_STRINGS && targLat1)
 649                             ? indexOfLatin1(value, valLen, targ, targLen, i)
 650                             : indexOf(value, valLen, targ, targLen, i))) > 0)
 651         {
 652             if (++p == pos.length) {
 653                 pos = Arrays.copyOf(pos, ArraysSupport.newCapacity(pos.length,
 654                                                                    1, p >> 1));
 655             }
 656             pos[p] = j;
 657             i = j + targLen;
 658         }
 659 
 660         int resultLen;
 661         try {
 662             resultLen = Math.addExact(valLen,
 663                     Math.multiplyExact(++p, replLen - targLen));
 664         } catch (ArithmeticException ignored) {
 665             throw new OutOfMemoryError();
 666         }
 667         if (resultLen == 0) {
 668             return "";
 669         }
 670 
 671         byte[] result = newBytesFor(resultLen);
 672         int posFrom = 0, posTo = 0;
 673         for (int q = 0; q < p; ++q) {
 674             int nextPos = pos[q];
 675             if (String.COMPACT_STRINGS && valLat1) {
 676                 while (posFrom < nextPos) {
 677                     char c = (char)(value[posFrom++] & 0xff);
 678                     putChar(result, posTo++, c);
 679                 }
 680             } else {
 681                 while (posFrom < nextPos) {
 682                     putChar(result, posTo++, getChar(value, posFrom++));
 683                 }
 684             }
 685             posFrom += targLen;
 686             if (String.COMPACT_STRINGS && replLat1) {
 687                 for (int k = 0; k < replLen; ++k) {
 688                     char c = (char)(repl[k] & 0xff);
 689                     putChar(result, posTo++, c);
 690                 }
 691             } else {
 692                 for (int k = 0; k < replLen; ++k) {
 693                     putChar(result, posTo++, getChar(repl, k));
 694                 }
 695             }
 696         }
 697         if (String.COMPACT_STRINGS && valLat1) {
 698             while (posFrom < valLen) {
 699                 char c = (char)(value[posFrom++] & 0xff);
 700                 putChar(result, posTo++, c);
 701             }
 702         } else {
 703             while (posFrom < valLen) {
 704                 putChar(result, posTo++, getChar(value, posFrom++));
 705             }
 706         }
 707 
 708         if (String.COMPACT_STRINGS && replLat1 && !targLat1) {
 709             // combination 6
 710             byte[] lat1Result = compress(result, 0, resultLen);
 711             if (lat1Result != null) {
 712                 return new String(lat1Result, LATIN1);
 713             }
 714         }
 715         return new String(result, UTF16);
 716     }
 717 
 718     public static boolean regionMatchesCI(byte[] value, int toffset,
 719                                           byte[] other, int ooffset, int len) {
 720         int last = toffset + len;
 721         assert toffset >= 0 && ooffset >= 0;
 722         assert ooffset + len <= length(other);
 723         assert last <= length(value);
 724         while (toffset < last) {
 725             char c1 = getChar(value, toffset++);
 726             char c2 = getChar(other, ooffset++);
 727             if (c1 == c2) {
 728                 continue;
 729             }
 730             // try converting both characters to uppercase.
 731             // If the results match, then the comparison scan should
 732             // continue.
 733             char u1 = Character.toUpperCase(c1);
 734             char u2 = Character.toUpperCase(c2);
 735             if (u1 == u2) {
 736                 continue;
 737             }
 738             // Unfortunately, conversion to uppercase does not work properly
 739             // for the Georgian alphabet, which has strange rules about case
 740             // conversion.  So we need to make one last check before
 741             // exiting.
 742             if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
 743                 continue;
 744             }
 745             return false;
 746         }
 747         return true;
 748     }
 749 
 750     public static boolean regionMatchesCI_Latin1(byte[] value, int toffset,
 751                                                  byte[] other, int ooffset,
 752                                                  int len) {
 753         return StringLatin1.regionMatchesCI_UTF16(other, ooffset, value, toffset, len);
 754     }
 755 
 756     public static String toLowerCase(String str, byte[] value, Locale locale) {
 757         if (locale == null) {
 758             throw new NullPointerException();
 759         }
 760         int first;
 761         boolean hasSurr = false;
 762         final int len = value.length >> 1;
 763 
 764         // Now check if there are any characters that need to be changed, or are surrogate
 765         for (first = 0 ; first < len; first++) {
 766             int cp = (int)getChar(value, first);
 767             if (Character.isSurrogate((char)cp)) {
 768                 hasSurr = true;
 769                 break;
 770             }
 771             if (cp != Character.toLowerCase(cp)) {  // no need to check Character.ERROR
 772                 break;
 773             }
 774         }
 775         if (first == len)
 776             return str;
 777         byte[] result = new byte[value.length];
 778         System.arraycopy(value, 0, result, 0, first << 1);  // Just copy the first few
 779                                                             // lowerCase characters.
 780         String lang = locale.getLanguage();
 781         if (lang == "tr" || lang == "az" || lang == "lt") {
 782             return toLowerCaseEx(str, value, result, first, locale, true);
 783         }
 784         if (hasSurr) {
 785             return toLowerCaseEx(str, value, result, first, locale, false);
 786         }
 787         int bits = 0;
 788         for (int i = first; i < len; i++) {
 789             int cp = (int)getChar(value, i);
 790             if (cp == '\u03A3' ||                       // GREEK CAPITAL LETTER SIGMA
 791                 Character.isSurrogate((char)cp)) {
 792                 return toLowerCaseEx(str, value, result, i, locale, false);
 793             }
 794             if (cp == '\u0130') {                       // LATIN CAPITAL LETTER I WITH DOT ABOVE
 795                 return toLowerCaseEx(str, value, result, i, locale, true);
 796             }
 797             cp = Character.toLowerCase(cp);
 798             if (!Character.isBmpCodePoint(cp)) {
 799                 return toLowerCaseEx(str, value, result, i, locale, false);
 800             }
 801             bits |= cp;
 802             putChar(result, i, cp);
 803         }
 804         if (bits > 0xFF) {
 805             return new String(result, UTF16);
 806         } else {
 807             return newString(result, 0, len);
 808         }
 809     }
 810 
 811     private static String toLowerCaseEx(String str, byte[] value,
 812                                         byte[] result, int first, Locale locale,
 813                                         boolean localeDependent) {
 814         assert(result.length == value.length);
 815         assert(first >= 0);
 816         int resultOffset = first;
 817         int length = value.length >> 1;
 818         int srcCount;
 819         for (int i = first; i < length; i += srcCount) {
 820             int srcChar = getChar(value, i);
 821             int lowerChar;
 822             char[] lowerCharArray;
 823             srcCount = 1;
 824             if (Character.isSurrogate((char)srcChar)) {
 825                 srcChar = codePointAt(value, i, length);
 826                 srcCount = Character.charCount(srcChar);
 827             }
 828             if (localeDependent ||
 829                 srcChar == '\u03A3' ||  // GREEK CAPITAL LETTER SIGMA
 830                 srcChar == '\u0130') {  // LATIN CAPITAL LETTER I WITH DOT ABOVE
 831                 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
 832             } else {
 833                 lowerChar = Character.toLowerCase(srcChar);
 834             }
 835             if (Character.isBmpCodePoint(lowerChar)) {    // Character.ERROR is not a bmp
 836                 putChar(result, resultOffset++, lowerChar);
 837             } else {
 838                 if (lowerChar == Character.ERROR) {
 839                     lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
 840                 } else {
 841                     lowerCharArray = Character.toChars(lowerChar);
 842                 }
 843                 /* Grow result if needed */
 844                 int mapLen = lowerCharArray.length;
 845                 if (mapLen > srcCount) {
 846                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 847                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 848                     result = result2;
 849                 }
 850                 assert resultOffset >= 0;
 851                 assert resultOffset + mapLen <= length(result);
 852                 for (int x = 0; x < mapLen; ++x) {
 853                     putChar(result, resultOffset++, lowerCharArray[x]);
 854                 }
 855             }
 856         }
 857         return newString(result, 0, resultOffset);
 858     }
 859 
 860     public static String toUpperCase(String str, byte[] value, Locale locale) {
 861         if (locale == null) {
 862             throw new NullPointerException();
 863         }
 864         int first;
 865         boolean hasSurr = false;
 866         final int len = value.length >> 1;
 867 
 868         // Now check if there are any characters that need to be changed, or are surrogate
 869         for (first = 0 ; first < len; first++) {
 870             int cp = (int)getChar(value, first);
 871             if (Character.isSurrogate((char)cp)) {
 872                 hasSurr = true;
 873                 break;
 874             }
 875             if (cp != Character.toUpperCaseEx(cp)) {   // no need to check Character.ERROR
 876                 break;
 877             }
 878         }
 879         if (first == len) {
 880             return str;
 881         }
 882         byte[] result = new byte[value.length];
 883         System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
 884                                                            // upperCase characters.
 885         String lang = locale.getLanguage();
 886         if (lang == "tr" || lang == "az" || lang == "lt") {
 887             return toUpperCaseEx(str, value, result, first, locale, true);
 888         }
 889         if (hasSurr) {
 890             return toUpperCaseEx(str, value, result, first, locale, false);
 891         }
 892         int bits = 0;
 893         for (int i = first; i < len; i++) {
 894             int cp = (int)getChar(value, i);
 895             if (Character.isSurrogate((char)cp)) {
 896                 return toUpperCaseEx(str, value, result, i, locale, false);
 897             }
 898             cp = Character.toUpperCaseEx(cp);
 899             if (!Character.isBmpCodePoint(cp)) {    // Character.ERROR is not bmp
 900                 return toUpperCaseEx(str, value, result, i, locale, false);
 901             }
 902             bits |= cp;
 903             putChar(result, i, cp);
 904         }
 905         if (bits > 0xFF) {
 906             return new String(result, UTF16);
 907         } else {
 908             return newString(result, 0, len);
 909         }
 910     }
 911 
 912     private static String toUpperCaseEx(String str, byte[] value,
 913                                         byte[] result, int first,
 914                                         Locale locale, boolean localeDependent)
 915     {
 916         assert(result.length == value.length);
 917         assert(first >= 0);
 918         int resultOffset = first;
 919         int length = value.length >> 1;
 920         int srcCount;
 921         for (int i = first; i < length; i += srcCount) {
 922             int srcChar = getChar(value, i);
 923             int upperChar;
 924             char[] upperCharArray;
 925             srcCount = 1;
 926             if (Character.isSurrogate((char)srcChar)) {
 927                 srcChar = codePointAt(value, i, length);
 928                 srcCount = Character.charCount(srcChar);
 929             }
 930             if (localeDependent) {
 931                 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
 932             } else {
 933                 upperChar = Character.toUpperCaseEx(srcChar);
 934             }
 935             if (Character.isBmpCodePoint(upperChar)) {
 936                 putChar(result, resultOffset++, upperChar);
 937             } else {
 938                 if (upperChar == Character.ERROR) {
 939                     if (localeDependent) {
 940                         upperCharArray =
 941                             ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
 942                     } else {
 943                         upperCharArray = Character.toUpperCaseCharArray(srcChar);
 944                     }
 945                 } else {
 946                     upperCharArray = Character.toChars(upperChar);
 947                 }
 948                 /* Grow result if needed */
 949                 int mapLen = upperCharArray.length;
 950                 if (mapLen > srcCount) {
 951                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 952                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 953                     result = result2;
 954                 }
 955                 assert resultOffset >= 0;
 956                 assert resultOffset + mapLen <= length(result);
 957                 for (int x = 0; x < mapLen; ++x) {
 958                     putChar(result, resultOffset++, upperCharArray[x]);
 959                 }
 960             }
 961         }
 962         return newString(result, 0, resultOffset);
 963     }
 964 
 965     public static String trim(byte[] value) {
 966         int length = value.length >> 1;
 967         int len = length;
 968         int st = 0;
 969         while (st < len && getChar(value, st) <= ' ') {
 970             st++;
 971         }
 972         while (st < len && getChar(value, len - 1) <= ' ') {
 973             len--;
 974         }
 975         return ((st > 0) || (len < length )) ?
 976             new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) :
 977             null;
 978     }
 979 
 980     public static int indexOfNonWhitespace(byte[] value) {
 981         int length = value.length >> 1;
 982         int left = 0;
 983         while (left < length) {
 984             int codepoint = codePointAt(value, left, length);
 985             if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) {
 986                 break;
 987             }
 988             left += Character.charCount(codepoint);
 989         }
 990         return left;
 991     }
 992 
 993     public static int lastIndexOfNonWhitespace(byte[] value) {
 994         int length = value.length >>> 1;
 995         int right = length;
 996         while (0 < right) {
 997             int codepoint = codePointBefore(value, right);
 998             if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) {
 999                 break;
1000             }
1001             right -= Character.charCount(codepoint);
1002         }
1003         return right;
1004     }
1005 
1006     public static String strip(byte[] value) {
1007         int length = value.length >>> 1;
1008         int left = indexOfNonWhitespace(value);
1009         if (left == length) {
1010             return "";
1011         }
1012         int right = lastIndexOfNonWhitespace(value);
1013         boolean ifChanged = (left > 0) || (right < length);
1014         return ifChanged ? newString(value, left, right - left) : null;
1015     }
1016 
1017     public static String stripLeading(byte[] value) {
1018         int length = value.length >>> 1;
1019         int left = indexOfNonWhitespace(value);
1020         if (left == length) {
1021             return "";
1022         }
1023         return (left != 0) ? newString(value, left, length - left) : null;
1024     }
1025 
1026     public static String stripTrailing(byte[] value) {
1027         int length = value.length >>> 1;
1028         int right = lastIndexOfNonWhitespace(value);
1029         if (right == 0) {
1030             return "";
1031         }
1032         return (right != length) ? newString(value, 0, right) : null;
1033     }
1034 
1035     private final static class LinesSpliterator implements Spliterator<String> {
1036         private byte[] value;
1037         private int index;        // current index, modified on advance/split
1038         private final int fence;  // one past last index
1039 
1040         private LinesSpliterator(byte[] value, int start, int length) {
1041             this.value = value;
1042             this.index = start;
1043             this.fence = start + length;
1044         }
1045 
1046         private int indexOfLineSeparator(int start) {
1047             for (int current = start; current < fence; current++) {
1048                 char ch = getChar(value, current);
1049                 if (ch == '\n' || ch == '\r') {
1050                     return current;
1051                 }
1052             }
1053             return fence;
1054         }
1055 
1056         private int skipLineSeparator(int start) {
1057             if (start < fence) {
1058                 if (getChar(value, start) == '\r') {
1059                     int next = start + 1;
1060                     if (next < fence && getChar(value, next) == '\n') {
1061                         return next + 1;
1062                     }
1063                 }
1064                 return start + 1;
1065             }
1066             return fence;
1067         }
1068 
1069         private String next() {
1070             int start = index;
1071             int end = indexOfLineSeparator(start);
1072             index = skipLineSeparator(end);
1073             return newString(value, start, end - start);
1074         }
1075 
1076         @Override
1077         public boolean tryAdvance(Consumer<? super String> action) {
1078             if (action == null) {
1079                 throw new NullPointerException("tryAdvance action missing");
1080             }
1081             if (index != fence) {
1082                 action.accept(next());
1083                 return true;
1084             }
1085             return false;
1086         }
1087 
1088         @Override
1089         public void forEachRemaining(Consumer<? super String> action) {
1090             if (action == null) {
1091                 throw new NullPointerException("forEachRemaining action missing");
1092             }
1093             while (index != fence) {
1094                 action.accept(next());
1095             }
1096         }
1097 
1098         @Override
1099         public Spliterator<String> trySplit() {
1100             int half = (fence + index) >>> 1;
1101             int mid = skipLineSeparator(indexOfLineSeparator(half));
1102             if (mid < fence) {
1103                 int start = index;
1104                 index = mid;
1105                 return new LinesSpliterator(value, start, mid - start);
1106             }
1107             return null;
1108         }
1109 
1110         @Override
1111         public long estimateSize() {
1112             return fence - index + 1;
1113         }
1114 
1115         @Override
1116         public int characteristics() {
1117             return Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL;
1118         }
1119 
1120         static LinesSpliterator spliterator(byte[] value) {
1121             return new LinesSpliterator(value, 0, value.length >>> 1);
1122         }
1123 
1124         static LinesSpliterator spliterator(byte[] value, int leading, int trailing) {
1125             int length = value.length >>> 1;
1126             int left = 0;
1127             int index;
1128             for (int l = 0; l < leading; l++) {
1129                 index = skipBlankForward(value, left, length);
1130                 if (index == left) {
1131                     break;
1132                 }
1133                 left = index;
1134             }
1135             int right = length;
1136             for (int t = 0; t < trailing; t++) {
1137                 index = skipBlankBackward(value, left, right);
1138                 if (index == right) {
1139                     break;
1140                 }
1141                 right = index;
1142             }
1143             return new LinesSpliterator(value, left, right - left);
1144         }
1145 
1146         private static int skipBlankForward(byte[] value, int start, int length) {
1147             int index = start;
1148             while (index < length) {
1149                 char ch = getChar(value, index++);
1150                 if (ch == '\n') {
1151                     return index;
1152                 }
1153                 if (ch == '\r') {
1154                     if (index < length && getChar(value, index) == '\n') {
1155                         return index + 1;
1156                     }
1157                     return index;
1158                 }
1159                 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) {
1160                     return start;
1161                 }
1162             }
1163             return length;
1164         }
1165 
1166         private static int skipBlankBackward(byte[] value, int start, int fence) {
1167             int index = fence;
1168             if (start < index && getChar(value, index - 1) == '\n') {
1169                 index--;
1170             }
1171             if (start < index && getChar(value, index - 1) == '\r') {
1172                 index--;
1173             }
1174             while (start < index) {
1175                 char ch = getChar(value, --index);
1176                 if (ch == '\r' || ch == '\n') {
1177                     return index + 1;
1178                 }
1179                 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) {
1180                     return fence;
1181                 }
1182             }
1183             return start;
1184         }
1185     }
1186 
1187     static Stream<String> lines(byte[] value, int leading, int trailing) {
1188         if (leading == 0 && trailing == 0) {
1189             return StreamSupport.stream(LinesSpliterator.spliterator(value), false);
1190         } else {
1191             return StreamSupport.stream(LinesSpliterator.spliterator(value, leading, trailing), false);
1192         }
1193     }
1194 
1195     private static void putChars(byte[] val, int index, char[] str, int off, int end) {
1196         while (off < end) {
1197             putChar(val, index++, str[off++]);
1198         }
1199     }
1200 
1201     public static String newString(byte[] val, int index, int len) {
1202         if (String.COMPACT_STRINGS) {
1203             byte[] buf = compress(val, index, len);
1204             if (buf != null) {
1205                 return new String(buf, LATIN1);
1206             }
1207         }
1208         int last = index + len;
1209         return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
1210     }
1211 
1212     public static void fillNull(byte[] val, int index, int end) {
1213         Arrays.fill(val, index << 1, end << 1, (byte)0);
1214     }
1215 
1216     static class CharsSpliterator implements Spliterator.OfInt {
1217         private final byte[] array;
1218         private int index;        // current index, modified on advance/split
1219         private final int fence;  // one past last index
1220         private final int cs;
1221 
1222         CharsSpliterator(byte[] array, int acs) {
1223             this(array, 0, array.length >> 1, acs);
1224         }
1225 
1226         CharsSpliterator(byte[] array, int origin, int fence, int acs) {
1227             this.array = array;
1228             this.index = origin;
1229             this.fence = fence;
1230             this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
1231                       | Spliterator.SUBSIZED;
1232         }
1233 
1234         @Override
1235         public OfInt trySplit() {
1236             int lo = index, mid = (lo + fence) >>> 1;
1237             return (lo >= mid)
1238                    ? null
1239                    : new CharsSpliterator(array, lo, index = mid, cs);
1240         }
1241 
1242         @Override
1243         public void forEachRemaining(IntConsumer action) {
1244             byte[] a; int i, hi; // hoist accesses and checks from loop
1245             if (action == null)
1246                 throw new NullPointerException();
1247             if (((a = array).length >> 1) >= (hi = fence) &&
1248                 (i = index) >= 0 && i < (index = hi)) {
1249                 do {
1250                     action.accept(charAt(a, i));
1251                 } while (++i < hi);
1252             }
1253         }
1254 
1255         @Override
1256         public boolean tryAdvance(IntConsumer action) {
1257             if (action == null)
1258                 throw new NullPointerException();
1259             int i = index;
1260             if (i >= 0 && i < fence) {
1261                 action.accept(charAt(array, i));
1262                 index++;
1263                 return true;
1264             }
1265             return false;
1266         }
1267 
1268         @Override
1269         public long estimateSize() { return (long)(fence - index); }
1270 
1271         @Override
1272         public int characteristics() {
1273             return cs;
1274         }
1275     }
1276 
1277     static class CodePointsSpliterator implements Spliterator.OfInt {
1278         private final byte[] array;
1279         private int index;        // current index, modified on advance/split
1280         private final int fence;  // one past last index
1281         private final int cs;
1282 
1283         CodePointsSpliterator(byte[] array, int acs) {
1284             this(array, 0, array.length >> 1, acs);
1285         }
1286 
1287         CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
1288             this.array = array;
1289             this.index = origin;
1290             this.fence = fence;
1291             this.cs = acs | Spliterator.ORDERED;
1292         }
1293 
1294         @Override
1295         public OfInt trySplit() {
1296             int lo = index, mid = (lo + fence) >>> 1;
1297             if (lo >= mid)
1298                 return null;
1299 
1300             int midOneLess;
1301             // If the mid-point intersects a surrogate pair
1302             if (Character.isLowSurrogate(charAt(array, mid)) &&
1303                 Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) {
1304                 // If there is only one pair it cannot be split
1305                 if (lo >= midOneLess)
1306                     return null;
1307                 // Shift the mid-point to align with the surrogate pair
1308                 return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
1309             }
1310             return new CodePointsSpliterator(array, lo, index = mid, cs);
1311         }
1312 
1313         @Override
1314         public void forEachRemaining(IntConsumer action) {
1315             byte[] a; int i, hi; // hoist accesses and checks from loop
1316             if (action == null)
1317                 throw new NullPointerException();
1318             if (((a = array).length >> 1) >= (hi = fence) &&
1319                 (i = index) >= 0 && i < (index = hi)) {
1320                 do {
1321                     i = advance(a, i, hi, action);
1322                 } while (i < hi);
1323             }
1324         }
1325 
1326         @Override
1327         public boolean tryAdvance(IntConsumer action) {
1328             if (action == null)
1329                 throw new NullPointerException();
1330             if (index >= 0 && index < fence) {
1331                 index = advance(array, index, fence, action);
1332                 return true;
1333             }
1334             return false;
1335         }
1336 
1337         // Advance one code point from the index, i, and return the next
1338         // index to advance from
1339         private static int advance(byte[] a, int i, int hi, IntConsumer action) {
1340             char c1 = charAt(a, i++);
1341             int cp = c1;
1342             if (Character.isHighSurrogate(c1) && i < hi) {
1343                 char c2 = charAt(a, i);
1344                 if (Character.isLowSurrogate(c2)) {
1345                     i++;
1346                     cp = Character.toCodePoint(c1, c2);
1347                 }
1348             }
1349             action.accept(cp);
1350             return i;
1351         }
1352 
1353         @Override
1354         public long estimateSize() { return (long)(fence - index); }
1355 
1356         @Override
1357         public int characteristics() {
1358             return cs;
1359         }
1360     }
1361 
1362     ////////////////////////////////////////////////////////////////
1363 
1364     public static void putCharSB(byte[] val, int index, int c) {
1365         checkIndex(index, val);
1366         putChar(val, index, c);
1367     }
1368 
1369     public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
1370         checkBoundsBeginEnd(index, index + end - off, val);
1371         putChars(val, index, ca, off, end);
1372     }
1373 
1374     public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
1375         checkBoundsBeginEnd(index, index + end - off, val);
1376         for (int i = off; i < end; i++) {
1377             putChar(val, index++, s.charAt(i));
1378         }
1379     }
1380 
1381     public static int codePointAtSB(byte[] val, int index, int end) {
1382         return codePointAt(val, index, end, true /* checked */);
1383     }
1384 
1385     public static int codePointBeforeSB(byte[] val, int index) {
1386         return codePointBefore(val, index, true /* checked */);
1387     }
1388 
1389     public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
1390         return codePointCount(val, beginIndex, endIndex, true /* checked */);
1391     }
1392 
1393     public static int getChars(int i, int begin, int end, byte[] value) {
1394         checkBoundsBeginEnd(begin, end, value);
1395         int pos = getChars(i, end, value);
1396         assert begin == pos;
1397         return pos;
1398     }
1399 
1400     public static int getChars(long l, int begin, int end, byte[] value) {
1401         checkBoundsBeginEnd(begin, end, value);
1402         int pos = getChars(l, end, value);
1403         assert begin == pos;
1404         return pos;
1405     }
1406 
1407     public static boolean contentEquals(byte[] v1, byte[] v2, int len) {
1408         checkBoundsOffCount(0, len, v2);
1409         for (int i = 0; i < len; i++) {
1410             if ((char)(v1[i] & 0xff) != getChar(v2, i)) {
1411                 return false;
1412             }
1413         }
1414         return true;
1415     }
1416 
1417     public static boolean contentEquals(byte[] value, CharSequence cs, int len) {
1418         checkOffset(len, value);
1419         for (int i = 0; i < len; i++) {
1420             if (getChar(value, i) != cs.charAt(i)) {
1421                 return false;
1422             }
1423         }
1424         return true;
1425     }
1426 
1427     public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) {
1428         int end = i + 4;
1429         checkBoundsBeginEnd(i, end, value);
1430         putChar(value, i++, c1);
1431         putChar(value, i++, c2);
1432         putChar(value, i++, c3);
1433         putChar(value, i++, c4);
1434         assert(i == end);
1435         return end;
1436     }
1437 
1438     public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) {
1439         int end = i + 5;
1440         checkBoundsBeginEnd(i, end, value);
1441         putChar(value, i++, c1);
1442         putChar(value, i++, c2);
1443         putChar(value, i++, c3);
1444         putChar(value, i++, c4);
1445         putChar(value, i++, c5);
1446         assert(i == end);
1447         return end;
1448     }
1449 
1450     public static char charAt(byte[] value, int index) {
1451         checkIndex(index, value);
1452         return getChar(value, index);
1453     }
1454 
1455     public static void reverse(byte[] val, int count) {
1456         checkOffset(count, val);
1457         int n = count - 1;
1458         boolean hasSurrogates = false;
1459         for (int j = (n-1) >> 1; j >= 0; j--) {
1460             int k = n - j;
1461             char cj = getChar(val, j);
1462             char ck = getChar(val, k);
1463             putChar(val, j, ck);
1464             putChar(val, k, cj);
1465             if (Character.isSurrogate(cj) ||
1466                 Character.isSurrogate(ck)) {
1467                 hasSurrogates = true;
1468             }
1469         }
1470         if (hasSurrogates) {
1471             reverseAllValidSurrogatePairs(val, count);
1472         }
1473     }
1474 
1475     /** Outlined helper method for reverse() */
1476     private static void reverseAllValidSurrogatePairs(byte[] val, int count) {
1477         for (int i = 0; i < count - 1; i++) {
1478             char c2 = getChar(val, i);
1479             if (Character.isLowSurrogate(c2)) {
1480                 char c1 = getChar(val, i + 1);
1481                 if (Character.isHighSurrogate(c1)) {
1482                     putChar(val, i++, c1);
1483                     putChar(val, i, c2);
1484                 }
1485             }
1486         }
1487     }
1488 
1489     // inflatedCopy byte[] -> byte[]
1490     public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
1491         // We need a range check here because 'putChar' has no checks
1492         checkBoundsOffCount(dstOff, len, dst);
1493         for (int i = 0; i < len; i++) {
1494             putChar(dst, dstOff++, src[srcOff++] & 0xff);
1495         }
1496     }
1497 
1498     // srcCoder == UTF16 && tgtCoder == LATIN1
1499     public static int lastIndexOfLatin1(byte[] src, int srcCount,
1500                                         byte[] tgt, int tgtCount, int fromIndex) {
1501         assert fromIndex >= 0;
1502         assert tgtCount > 0;
1503         assert tgtCount <= tgt.length;
1504         int min = tgtCount - 1;
1505         int i = min + fromIndex;
1506         int strLastIndex = tgtCount - 1;
1507 
1508         char strLastChar = (char)(tgt[strLastIndex] & 0xff);
1509 
1510         checkIndex(i, src);
1511 
1512     startSearchForLastChar:
1513         while (true) {
1514             while (i >= min && getChar(src, i) != strLastChar) {
1515                 i--;
1516             }
1517             if (i < min) {
1518                 return -1;
1519             }
1520             int j = i - 1;
1521             int start = j - strLastIndex;
1522             int k = strLastIndex - 1;
1523             while (j > start) {
1524                 if (getChar(src, j--) != (tgt[k--] & 0xff)) {
1525                     i--;
1526                     continue startSearchForLastChar;
1527                 }
1528             }
1529             return start + 1;
1530         }
1531     }
1532 
1533     ////////////////////////////////////////////////////////////////
1534 
1535     private static native boolean isBigEndian();
1536 
1537     static final int HI_BYTE_SHIFT;
1538     static final int LO_BYTE_SHIFT;
1539     static {
1540         if (isBigEndian()) {
1541             HI_BYTE_SHIFT = 8;
1542             LO_BYTE_SHIFT = 0;
1543         } else {
1544             HI_BYTE_SHIFT = 0;
1545             LO_BYTE_SHIFT = 8;
1546         }
1547     }
1548 
1549     static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
1550 
1551     // Used by trusted callers.  Assumes all necessary bounds checks have
1552     // been done by the caller.
1553 
1554     /**
1555      * This is a variant of {@link Integer#getChars(int, int, byte[])}, but for
1556      * UTF-16 coder.
1557      *
1558      * @param i     value to convert
1559      * @param index next index, after the least significant digit
1560      * @param buf   target buffer, UTF16-coded.
1561      * @return index of the most significant digit or minus sign, if present
1562      */
1563     static int getChars(int i, int index, byte[] buf) {
1564         int q, r;
1565         int charPos = index;
1566 
1567         boolean negative = (i < 0);
1568         if (!negative) {
1569             i = -i;
1570         }
1571 
1572         // Get 2 digits/iteration using ints
1573         while (i <= -100) {
1574             q = i / 100;
1575             r = (q * 100) - i;
1576             i = q;
1577             putChar(buf, --charPos, Integer.DigitOnes[r]);
1578             putChar(buf, --charPos, Integer.DigitTens[r]);
1579         }
1580 
1581         // We know there are at most two digits left at this point.
1582         q = i / 10;
1583         r = (q * 10) - i;
1584         putChar(buf, --charPos, '0' + r);
1585 
1586         // Whatever left is the remaining digit.
1587         if (q < 0) {
1588             putChar(buf, --charPos, '0' - q);
1589         }
1590 
1591         if (negative) {
1592             putChar(buf, --charPos, '-');
1593         }
1594         return charPos;
1595     }
1596 
1597     /**
1598      * This is a variant of {@link Long#getChars(long, int, byte[])}, but for
1599      * UTF-16 coder.
1600      *
1601      * @param i     value to convert
1602      * @param index next index, after the least significant digit
1603      * @param buf   target buffer, UTF16-coded.
1604      * @return index of the most significant digit or minus sign, if present
1605      */
1606     static int getChars(long i, int index, byte[] buf) {
1607         long q;
1608         int r;
1609         int charPos = index;
1610 
1611         boolean negative = (i < 0);
1612         if (!negative) {
1613             i = -i;
1614         }
1615 
1616         // Get 2 digits/iteration using longs until quotient fits into an int
1617         while (i <= Integer.MIN_VALUE) {
1618             q = i / 100;
1619             r = (int)((q * 100) - i);
1620             i = q;
1621             putChar(buf, --charPos, Integer.DigitOnes[r]);
1622             putChar(buf, --charPos, Integer.DigitTens[r]);
1623         }
1624 
1625         // Get 2 digits/iteration using ints
1626         int q2;
1627         int i2 = (int)i;
1628         while (i2 <= -100) {
1629             q2 = i2 / 100;
1630             r  = (q2 * 100) - i2;
1631             i2 = q2;
1632             putChar(buf, --charPos, Integer.DigitOnes[r]);
1633             putChar(buf, --charPos, Integer.DigitTens[r]);
1634         }
1635 
1636         // We know there are at most two digits left at this point.
1637         q2 = i2 / 10;
1638         r  = (q2 * 10) - i2;
1639         putChar(buf, --charPos, '0' + r);
1640 
1641         // Whatever left is the remaining digit.
1642         if (q2 < 0) {
1643             putChar(buf, --charPos, '0' - q2);
1644         }
1645 
1646         if (negative) {
1647             putChar(buf, --charPos, '-');
1648         }
1649         return charPos;
1650     }
1651     // End of trusted methods.
1652 
1653     public static void checkIndex(int off, byte[] val) {
1654         String.checkIndex(off, length(val));
1655     }
1656 
1657     public static void checkOffset(int off, byte[] val) {
1658         String.checkOffset(off, length(val));
1659     }
1660 
1661     public static void checkBoundsBeginEnd(int begin, int end, byte[] val) {
1662         String.checkBoundsBeginEnd(begin, end, length(val));
1663     }
1664 
1665     public static void checkBoundsOffCount(int offset, int count, byte[] val) {
1666         String.checkBoundsOffCount(offset, count, length(val));
1667     }
1668 
1669 }