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         static LinesSpliterator spliterator(byte[] value, int leading, int trailing) {
1131             int length = value.length >>> 1;
1132             int left = 0;
1133             int index;
1134             for (int l = 0; l < leading; l++) {
1135                 index = skipBlankForward(value, left, length);
1136                 if (index == left) {
1137                     break;
1138                 }
1139                 left = index;
1140             }
1141             int right = length;
1142             for (int t = 0; t < trailing; t++) {
1143                 index = skipBlankBackward(value, left, right);
1144                 if (index == right) {
1145                     break;
1146                 }
1147                 right = index;
1148             }
1149             return new LinesSpliterator(value, left, right - left);
1150         }
1151 
1152         private static int skipBlankForward(byte[] value, int start, int length) {
1153             int index = start;
1154             while (index < length) {
1155                 char ch = getChar(value, index++);
1156                 if (ch == '\n') {
1157                     return index;
1158                 }
1159                 if (ch == '\r') {
1160                     if (index < length && getChar(value, index) == '\n') {
1161                         return index + 1;
1162                     }
1163                     return index;
1164                 }
1165                 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) {
1166                     return start;
1167                 }
1168             }
1169             return length;
1170         }
1171 
1172         private static int skipBlankBackward(byte[] value, int start, int fence) {
1173             int index = fence;
1174             if (start < index && getChar(value, index - 1) == '\n') {
1175                 index--;
1176             }
1177             if (start < index && getChar(value, index - 1) == '\r') {
1178                 index--;
1179             }
1180             while (start < index) {
1181                 char ch = getChar(value, --index);
1182                 if (ch == '\r' || ch == '\n') {
1183                     return index + 1;
1184                 }
1185                 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) {
1186                     return fence;
1187                 }
1188             }
1189             return start;
1190         }
1191     }
1192 
1193     static Stream<String> lines(byte[] value, int leading, int trailing) {
1194         if (leading == 0 && trailing == 0) {
1195             return StreamSupport.stream(LinesSpliterator.spliterator(value), false);
1196         } else {
1197             return StreamSupport.stream(LinesSpliterator.spliterator(value, leading, trailing), false);
1198         }
1199     }
1200 
1201     private static void putChars(byte[] val, int index, char[] str, int off, int end) {
1202         while (off < end) {
1203             putChar(val, index++, str[off++]);
1204         }
1205     }
1206 
1207     public static String newString(byte[] val, int index, int len) {
1208         if (String.COMPACT_STRINGS) {
1209             byte[] buf = compress(val, index, len);
1210             if (buf != null) {
1211                 return new String(buf, LATIN1);
1212             }
1213         }
1214         int last = index + len;
1215         return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
1216     }
1217 
1218     public static void fillNull(byte[] val, int index, int end) {
1219         Arrays.fill(val, index << 1, end << 1, (byte)0);
1220     }
1221 
1222     static class CharsSpliterator implements Spliterator.OfInt {
1223         private final byte[] array;
1224         private int index;        // current index, modified on advance/split
1225         private final int fence;  // one past last index
1226         private final int cs;
1227 
1228         CharsSpliterator(byte[] array, int acs) {
1229             this(array, 0, array.length >> 1, acs);
1230         }
1231 
1232         CharsSpliterator(byte[] array, int origin, int fence, int acs) {
1233             this.array = array;
1234             this.index = origin;
1235             this.fence = fence;
1236             this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
1237                       | Spliterator.SUBSIZED;
1238         }
1239 
1240         @Override
1241         public OfInt trySplit() {
1242             int lo = index, mid = (lo + fence) >>> 1;
1243             return (lo >= mid)
1244                    ? null
1245                    : new CharsSpliterator(array, lo, index = mid, cs);
1246         }
1247 
1248         @Override
1249         public void forEachRemaining(IntConsumer action) {
1250             byte[] a; int i, hi; // hoist accesses and checks from loop
1251             if (action == null)
1252                 throw new NullPointerException();
1253             if (((a = array).length >> 1) >= (hi = fence) &&
1254                 (i = index) >= 0 && i < (index = hi)) {
1255                 do {
1256                     action.accept(charAt(a, i));
1257                 } while (++i < hi);
1258             }
1259         }
1260 
1261         @Override
1262         public boolean tryAdvance(IntConsumer action) {
1263             if (action == null)
1264                 throw new NullPointerException();
1265             int i = index;
1266             if (i >= 0 && i < fence) {
1267                 action.accept(charAt(array, i));
1268                 index++;
1269                 return true;
1270             }
1271             return false;
1272         }
1273 
1274         @Override
1275         public long estimateSize() { return (long)(fence - index); }
1276 
1277         @Override
1278         public int characteristics() {
1279             return cs;
1280         }
1281     }
1282 
1283     static class CodePointsSpliterator implements Spliterator.OfInt {
1284         private final byte[] array;
1285         private int index;        // current index, modified on advance/split
1286         private final int fence;  // one past last index
1287         private final int cs;
1288 
1289         CodePointsSpliterator(byte[] array, int acs) {
1290             this(array, 0, array.length >> 1, acs);
1291         }
1292 
1293         CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
1294             this.array = array;
1295             this.index = origin;
1296             this.fence = fence;
1297             this.cs = acs | Spliterator.ORDERED;
1298         }
1299 
1300         @Override
1301         public OfInt trySplit() {
1302             int lo = index, mid = (lo + fence) >>> 1;
1303             if (lo >= mid)
1304                 return null;
1305 
1306             int midOneLess;
1307             // If the mid-point intersects a surrogate pair
1308             if (Character.isLowSurrogate(charAt(array, mid)) &&
1309                 Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) {
1310                 // If there is only one pair it cannot be split
1311                 if (lo >= midOneLess)
1312                     return null;
1313                 // Shift the mid-point to align with the surrogate pair
1314                 return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
1315             }
1316             return new CodePointsSpliterator(array, lo, index = mid, cs);
1317         }
1318 
1319         @Override
1320         public void forEachRemaining(IntConsumer action) {
1321             byte[] a; int i, hi; // hoist accesses and checks from loop
1322             if (action == null)
1323                 throw new NullPointerException();
1324             if (((a = array).length >> 1) >= (hi = fence) &&
1325                 (i = index) >= 0 && i < (index = hi)) {
1326                 do {
1327                     i = advance(a, i, hi, action);
1328                 } while (i < hi);
1329             }
1330         }
1331 
1332         @Override
1333         public boolean tryAdvance(IntConsumer action) {
1334             if (action == null)
1335                 throw new NullPointerException();
1336             if (index >= 0 && index < fence) {
1337                 index = advance(array, index, fence, action);
1338                 return true;
1339             }
1340             return false;
1341         }
1342 
1343         // Advance one code point from the index, i, and return the next
1344         // index to advance from
1345         private static int advance(byte[] a, int i, int hi, IntConsumer action) {
1346             char c1 = charAt(a, i++);
1347             int cp = c1;
1348             if (Character.isHighSurrogate(c1) && i < hi) {
1349                 char c2 = charAt(a, i);
1350                 if (Character.isLowSurrogate(c2)) {
1351                     i++;
1352                     cp = Character.toCodePoint(c1, c2);
1353                 }
1354             }
1355             action.accept(cp);
1356             return i;
1357         }
1358 
1359         @Override
1360         public long estimateSize() { return (long)(fence - index); }
1361 
1362         @Override
1363         public int characteristics() {
1364             return cs;
1365         }
1366     }
1367 
1368     ////////////////////////////////////////////////////////////////
1369 
1370     public static void putCharSB(byte[] val, int index, int c) {
1371         checkIndex(index, val);
1372         putChar(val, index, c);
1373     }
1374 
1375     public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
1376         checkBoundsBeginEnd(index, index + end - off, val);
1377         putChars(val, index, ca, off, end);
1378     }
1379 
1380     public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
1381         checkBoundsBeginEnd(index, index + end - off, val);
1382         for (int i = off; i < end; i++) {
1383             putChar(val, index++, s.charAt(i));
1384         }
1385     }
1386 
1387     public static int codePointAtSB(byte[] val, int index, int end) {
1388         return codePointAt(val, index, end, true /* checked */);
1389     }
1390 
1391     public static int codePointBeforeSB(byte[] val, int index) {
1392         return codePointBefore(val, index, true /* checked */);
1393     }
1394 
1395     public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
1396         return codePointCount(val, beginIndex, endIndex, true /* checked */);
1397     }
1398 
1399     public static int getChars(int i, int begin, int end, byte[] value) {
1400         checkBoundsBeginEnd(begin, end, value);
1401         int pos = getChars(i, end, value);
1402         assert begin == pos;
1403         return pos;
1404     }
1405 
1406     public static int getChars(long l, int begin, int end, byte[] value) {
1407         checkBoundsBeginEnd(begin, end, value);
1408         int pos = getChars(l, end, value);
1409         assert begin == pos;
1410         return pos;
1411     }
1412 
1413     public static boolean contentEquals(byte[] v1, byte[] v2, int len) {
1414         checkBoundsOffCount(0, len, v2);
1415         for (int i = 0; i < len; i++) {
1416             if ((char)(v1[i] & 0xff) != getChar(v2, i)) {
1417                 return false;
1418             }
1419         }
1420         return true;
1421     }
1422 
1423     public static boolean contentEquals(byte[] value, CharSequence cs, int len) {
1424         checkOffset(len, value);
1425         for (int i = 0; i < len; i++) {
1426             if (getChar(value, i) != cs.charAt(i)) {
1427                 return false;
1428             }
1429         }
1430         return true;
1431     }
1432 
1433     public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) {
1434         int end = i + 4;
1435         checkBoundsBeginEnd(i, end, value);
1436         putChar(value, i++, c1);
1437         putChar(value, i++, c2);
1438         putChar(value, i++, c3);
1439         putChar(value, i++, c4);
1440         assert(i == end);
1441         return end;
1442     }
1443 
1444     public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) {
1445         int end = i + 5;
1446         checkBoundsBeginEnd(i, end, value);
1447         putChar(value, i++, c1);
1448         putChar(value, i++, c2);
1449         putChar(value, i++, c3);
1450         putChar(value, i++, c4);
1451         putChar(value, i++, c5);
1452         assert(i == end);
1453         return end;
1454     }
1455 
1456     public static char charAt(byte[] value, int index) {
1457         checkIndex(index, value);
1458         return getChar(value, index);
1459     }
1460 
1461     public static void reverse(byte[] val, int count) {
1462         checkOffset(count, val);
1463         int n = count - 1;
1464         boolean hasSurrogates = false;
1465         for (int j = (n-1) >> 1; j >= 0; j--) {
1466             int k = n - j;
1467             char cj = getChar(val, j);
1468             char ck = getChar(val, k);
1469             putChar(val, j, ck);
1470             putChar(val, k, cj);
1471             if (Character.isSurrogate(cj) ||
1472                 Character.isSurrogate(ck)) {
1473                 hasSurrogates = true;
1474             }
1475         }
1476         if (hasSurrogates) {
1477             reverseAllValidSurrogatePairs(val, count);
1478         }
1479     }
1480 
1481     /** Outlined helper method for reverse() */
1482     private static void reverseAllValidSurrogatePairs(byte[] val, int count) {
1483         for (int i = 0; i < count - 1; i++) {
1484             char c2 = getChar(val, i);
1485             if (Character.isLowSurrogate(c2)) {
1486                 char c1 = getChar(val, i + 1);
1487                 if (Character.isHighSurrogate(c1)) {
1488                     putChar(val, i++, c1);
1489                     putChar(val, i, c2);
1490                 }
1491             }
1492         }
1493     }
1494 
1495     // inflatedCopy byte[] -> byte[]
1496     public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
1497         // We need a range check here because 'putChar' has no checks
1498         checkBoundsOffCount(dstOff, len, dst);
1499         for (int i = 0; i < len; i++) {
1500             putChar(dst, dstOff++, src[srcOff++] & 0xff);
1501         }
1502     }
1503 
1504     // srcCoder == UTF16 && tgtCoder == LATIN1
1505     public static int lastIndexOfLatin1(byte[] src, int srcCount,
1506                                         byte[] tgt, int tgtCount, int fromIndex) {
1507         assert fromIndex >= 0;
1508         assert tgtCount > 0;
1509         assert tgtCount <= tgt.length;
1510         int min = tgtCount - 1;
1511         int i = min + fromIndex;
1512         int strLastIndex = tgtCount - 1;
1513 
1514         char strLastChar = (char)(tgt[strLastIndex] & 0xff);
1515 
1516         checkIndex(i, src);
1517 
1518     startSearchForLastChar:
1519         while (true) {
1520             while (i >= min && getChar(src, i) != strLastChar) {
1521                 i--;
1522             }
1523             if (i < min) {
1524                 return -1;
1525             }
1526             int j = i - 1;
1527             int start = j - strLastIndex;
1528             int k = strLastIndex - 1;
1529             while (j > start) {
1530                 if (getChar(src, j--) != (tgt[k--] & 0xff)) {
1531                     i--;
1532                     continue startSearchForLastChar;
1533                 }
1534             }
1535             return start + 1;
1536         }
1537     }
1538 
1539     ////////////////////////////////////////////////////////////////
1540 
1541     private static native boolean isBigEndian();
1542 
1543     static final int HI_BYTE_SHIFT;
1544     static final int LO_BYTE_SHIFT;
1545     static {
1546         if (isBigEndian()) {
1547             HI_BYTE_SHIFT = 8;
1548             LO_BYTE_SHIFT = 0;
1549         } else {
1550             HI_BYTE_SHIFT = 0;
1551             LO_BYTE_SHIFT = 8;
1552         }
1553     }
1554 
1555     static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
1556 
1557 
1558     /**
1559      * The maximum size of array to allocate (unless necessary).
1560      * Some VMs reserve some header words in an array.
1561      * Attempts to allocate larger arrays may result in
1562      * OutOfMemoryError: Requested array size exceeds VM limit
1563      */
1564     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
1565 
1566     // Used by trusted callers.  Assumes all necessary bounds checks have
1567     // been done by the caller.
1568 
1569     /**
1570      * This is a variant of {@link Integer#getChars(int, int, byte[])}, but for
1571      * UTF-16 coder.
1572      *
1573      * @param i     value to convert
1574      * @param index next index, after the least significant digit
1575      * @param buf   target buffer, UTF16-coded.
1576      * @return index of the most significant digit or minus sign, if present
1577      */
1578     static int getChars(int i, int index, byte[] buf) {
1579         int q, r;
1580         int charPos = index;
1581 
1582         boolean negative = (i < 0);
1583         if (!negative) {
1584             i = -i;
1585         }
1586 
1587         // Get 2 digits/iteration using ints
1588         while (i <= -100) {
1589             q = i / 100;
1590             r = (q * 100) - i;
1591             i = q;
1592             putChar(buf, --charPos, Integer.DigitOnes[r]);
1593             putChar(buf, --charPos, Integer.DigitTens[r]);
1594         }
1595 
1596         // We know there are at most two digits left at this point.
1597         q = i / 10;
1598         r = (q * 10) - i;
1599         putChar(buf, --charPos, '0' + r);
1600 
1601         // Whatever left is the remaining digit.
1602         if (q < 0) {
1603             putChar(buf, --charPos, '0' - q);
1604         }
1605 
1606         if (negative) {
1607             putChar(buf, --charPos, '-');
1608         }
1609         return charPos;
1610     }
1611 
1612     /**
1613      * This is a variant of {@link Long#getChars(long, int, byte[])}, but for
1614      * UTF-16 coder.
1615      *
1616      * @param i     value to convert
1617      * @param index next index, after the least significant digit
1618      * @param buf   target buffer, UTF16-coded.
1619      * @return index of the most significant digit or minus sign, if present
1620      */
1621     static int getChars(long i, int index, byte[] buf) {
1622         long q;
1623         int r;
1624         int charPos = index;
1625 
1626         boolean negative = (i < 0);
1627         if (!negative) {
1628             i = -i;
1629         }
1630 
1631         // Get 2 digits/iteration using longs until quotient fits into an int
1632         while (i <= Integer.MIN_VALUE) {
1633             q = i / 100;
1634             r = (int)((q * 100) - i);
1635             i = q;
1636             putChar(buf, --charPos, Integer.DigitOnes[r]);
1637             putChar(buf, --charPos, Integer.DigitTens[r]);
1638         }
1639 
1640         // Get 2 digits/iteration using ints
1641         int q2;
1642         int i2 = (int)i;
1643         while (i2 <= -100) {
1644             q2 = i2 / 100;
1645             r  = (q2 * 100) - i2;
1646             i2 = q2;
1647             putChar(buf, --charPos, Integer.DigitOnes[r]);
1648             putChar(buf, --charPos, Integer.DigitTens[r]);
1649         }
1650 
1651         // We know there are at most two digits left at this point.
1652         q2 = i2 / 10;
1653         r  = (q2 * 10) - i2;
1654         putChar(buf, --charPos, '0' + r);
1655 
1656         // Whatever left is the remaining digit.
1657         if (q2 < 0) {
1658             putChar(buf, --charPos, '0' - q2);
1659         }
1660 
1661         if (negative) {
1662             putChar(buf, --charPos, '-');
1663         }
1664         return charPos;
1665     }
1666     // End of trusted methods.
1667 
1668     public static void checkIndex(int off, byte[] val) {
1669         String.checkIndex(off, length(val));
1670     }
1671 
1672     public static void checkOffset(int off, byte[] val) {
1673         String.checkOffset(off, length(val));
1674     }
1675 
1676     public static void checkBoundsBeginEnd(int begin, int end, byte[] val) {
1677         String.checkBoundsBeginEnd(begin, end, length(val));
1678     }
1679 
1680     public static void checkBoundsOffCount(int offset, int count, byte[] val) {
1681         String.checkBoundsOffCount(offset, count, length(val));
1682     }
1683 
1684 }