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