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 boolean regionMatchesCI(byte[] value, int toffset,
 601                                           byte[] other, int ooffset, int len) {
 602         int last = toffset + len;
 603         assert toffset >= 0 && ooffset >= 0;
 604         assert ooffset + len <= length(other);
 605         assert last <= length(value);
 606         while (toffset < last) {
 607             char c1 = getChar(value, toffset++);
 608             char c2 = getChar(other, ooffset++);
 609             if (c1 == c2) {
 610                 continue;
 611             }
 612             // try converting both characters to uppercase.
 613             // If the results match, then the comparison scan should
 614             // continue.
 615             char u1 = Character.toUpperCase(c1);
 616             char u2 = Character.toUpperCase(c2);
 617             if (u1 == u2) {
 618                 continue;
 619             }
 620             // Unfortunately, conversion to uppercase does not work properly
 621             // for the Georgian alphabet, which has strange rules about case
 622             // conversion.  So we need to make one last check before
 623             // exiting.
 624             if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
 625                 continue;
 626             }
 627             return false;
 628         }
 629         return true;
 630     }
 631 
 632     public static boolean regionMatchesCI_Latin1(byte[] value, int toffset,
 633                                                  byte[] other, int ooffset,
 634                                                  int len) {
 635         return StringLatin1.regionMatchesCI_UTF16(other, ooffset, value, toffset, len);
 636     }
 637 
 638     public static String toLowerCase(String str, byte[] value, Locale locale) {
 639         if (locale == null) {
 640             throw new NullPointerException();
 641         }
 642         int first;
 643         boolean hasSurr = false;
 644         final int len = value.length >> 1;
 645 
 646         // Now check if there are any characters that need to be changed, or are surrogate
 647         for (first = 0 ; first < len; first++) {
 648             int cp = (int)getChar(value, first);
 649             if (Character.isSurrogate((char)cp)) {
 650                 hasSurr = true;
 651                 break;
 652             }
 653             if (cp != Character.toLowerCase(cp)) {  // no need to check Character.ERROR
 654                 break;
 655             }
 656         }
 657         if (first == len)
 658             return str;
 659         byte[] result = new byte[value.length];
 660         System.arraycopy(value, 0, result, 0, first << 1);  // Just copy the first few
 661                                                             // lowerCase characters.
 662         String lang = locale.getLanguage();
 663         if (lang == "tr" || lang == "az" || lang == "lt") {
 664             return toLowerCaseEx(str, value, result, first, locale, true);
 665         }
 666         if (hasSurr) {
 667             return toLowerCaseEx(str, value, result, first, locale, false);
 668         }
 669         int bits = 0;
 670         for (int i = first; i < len; i++) {
 671             int cp = (int)getChar(value, i);
 672             if (cp == '\u03A3' ||                       // GREEK CAPITAL LETTER SIGMA
 673                 Character.isSurrogate((char)cp)) {
 674                 return toLowerCaseEx(str, value, result, i, locale, false);
 675             }
 676             if (cp == '\u0130') {                       // LATIN CAPITAL LETTER I WITH DOT ABOVE
 677                 return toLowerCaseEx(str, value, result, i, locale, true);
 678             }
 679             cp = Character.toLowerCase(cp);
 680             if (!Character.isBmpCodePoint(cp)) {
 681                 return toLowerCaseEx(str, value, result, i, locale, false);
 682             }
 683             bits |= cp;
 684             putChar(result, i, cp);
 685         }
 686         if (bits > 0xFF) {
 687             return new String(result, UTF16);
 688         } else {
 689             return newString(result, 0, len);
 690         }
 691     }
 692 
 693     private static String toLowerCaseEx(String str, byte[] value,
 694                                         byte[] result, int first, Locale locale,
 695                                         boolean localeDependent) {
 696         assert(result.length == value.length);
 697         assert(first >= 0);
 698         int resultOffset = first;
 699         int length = value.length >> 1;
 700         int srcCount;
 701         for (int i = first; i < length; i += srcCount) {
 702             int srcChar = getChar(value, i);
 703             int lowerChar;
 704             char[] lowerCharArray;
 705             srcCount = 1;
 706             if (Character.isSurrogate((char)srcChar)) {
 707                 srcChar = codePointAt(value, i, length);
 708                 srcCount = Character.charCount(srcChar);
 709             }
 710             if (localeDependent ||
 711                 srcChar == '\u03A3' ||  // GREEK CAPITAL LETTER SIGMA
 712                 srcChar == '\u0130') {  // LATIN CAPITAL LETTER I WITH DOT ABOVE
 713                 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
 714             } else {
 715                 lowerChar = Character.toLowerCase(srcChar);
 716             }
 717             if (Character.isBmpCodePoint(lowerChar)) {    // Character.ERROR is not a bmp
 718                 putChar(result, resultOffset++, lowerChar);
 719             } else {
 720                 if (lowerChar == Character.ERROR) {
 721                     lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
 722                 } else {
 723                     lowerCharArray = Character.toChars(lowerChar);
 724                 }
 725                 /* Grow result if needed */
 726                 int mapLen = lowerCharArray.length;
 727                 if (mapLen > srcCount) {
 728                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 729                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 730                     result = result2;
 731                 }
 732                 assert resultOffset >= 0;
 733                 assert resultOffset + mapLen <= length(result);
 734                 for (int x = 0; x < mapLen; ++x) {
 735                     putChar(result, resultOffset++, lowerCharArray[x]);
 736                 }
 737             }
 738         }
 739         return newString(result, 0, resultOffset);
 740     }
 741 
 742     public static String toUpperCase(String str, byte[] value, Locale locale) {
 743         if (locale == null) {
 744             throw new NullPointerException();
 745         }
 746         int first;
 747         boolean hasSurr = false;
 748         final int len = value.length >> 1;
 749 
 750         // Now check if there are any characters that need to be changed, or are surrogate
 751         for (first = 0 ; first < len; first++) {
 752             int cp = (int)getChar(value, first);
 753             if (Character.isSurrogate((char)cp)) {
 754                 hasSurr = true;
 755                 break;
 756             }
 757             if (cp != Character.toUpperCaseEx(cp)) {   // no need to check Character.ERROR
 758                 break;
 759             }
 760         }
 761         if (first == len) {
 762             return str;
 763         }
 764         byte[] result = new byte[value.length];
 765         System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
 766                                                            // upperCase characters.
 767         String lang = locale.getLanguage();
 768         if (lang == "tr" || lang == "az" || lang == "lt") {
 769             return toUpperCaseEx(str, value, result, first, locale, true);
 770         }
 771         if (hasSurr) {
 772             return toUpperCaseEx(str, value, result, first, locale, false);
 773         }
 774         int bits = 0;
 775         for (int i = first; i < len; i++) {
 776             int cp = (int)getChar(value, i);
 777             if (Character.isSurrogate((char)cp)) {
 778                 return toUpperCaseEx(str, value, result, i, locale, false);
 779             }
 780             cp = Character.toUpperCaseEx(cp);
 781             if (!Character.isBmpCodePoint(cp)) {    // Character.ERROR is not bmp
 782                 return toUpperCaseEx(str, value, result, i, locale, false);
 783             }
 784             bits |= cp;
 785             putChar(result, i, cp);
 786         }
 787         if (bits > 0xFF) {
 788             return new String(result, UTF16);
 789         } else {
 790             return newString(result, 0, len);
 791         }
 792     }
 793 
 794     private static String toUpperCaseEx(String str, byte[] value,
 795                                         byte[] result, int first,
 796                                         Locale locale, boolean localeDependent)
 797     {
 798         assert(result.length == value.length);
 799         assert(first >= 0);
 800         int resultOffset = first;
 801         int length = value.length >> 1;
 802         int srcCount;
 803         for (int i = first; i < length; i += srcCount) {
 804             int srcChar = getChar(value, i);
 805             int upperChar;
 806             char[] upperCharArray;
 807             srcCount = 1;
 808             if (Character.isSurrogate((char)srcChar)) {
 809                 srcChar = codePointAt(value, i, length);
 810                 srcCount = Character.charCount(srcChar);
 811             }
 812             if (localeDependent) {
 813                 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
 814             } else {
 815                 upperChar = Character.toUpperCaseEx(srcChar);
 816             }
 817             if (Character.isBmpCodePoint(upperChar)) {
 818                 putChar(result, resultOffset++, upperChar);
 819             } else {
 820                 if (upperChar == Character.ERROR) {
 821                     if (localeDependent) {
 822                         upperCharArray =
 823                             ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
 824                     } else {
 825                         upperCharArray = Character.toUpperCaseCharArray(srcChar);
 826                     }
 827                 } else {
 828                     upperCharArray = Character.toChars(upperChar);
 829                 }
 830                 /* Grow result if needed */
 831                 int mapLen = upperCharArray.length;
 832                 if (mapLen > srcCount) {
 833                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 834                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 835                     result = result2;
 836                 }
 837                 assert resultOffset >= 0;
 838                 assert resultOffset + mapLen <= length(result);
 839                 for (int x = 0; x < mapLen; ++x) {
 840                     putChar(result, resultOffset++, upperCharArray[x]);
 841                 }
 842             }
 843         }
 844         return newString(result, 0, resultOffset);
 845     }
 846 
 847     public static String trim(byte[] value) {
 848         int length = value.length >> 1;
 849         int len = length;
 850         int st = 0;
 851         while (st < len && getChar(value, st) <= ' ') {
 852             st++;
 853         }
 854         while (st < len && getChar(value, len - 1) <= ' ') {
 855             len--;
 856         }
 857         return ((st > 0) || (len < length )) ?
 858             new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) :
 859             null;
 860     }
 861 
 862     public static int indexOfNonWhitespace(byte[] value) {
 863         int length = value.length >> 1;
 864         int left = 0;
 865         while (left < length) {
 866             int codepoint = codePointAt(value, left, length);
 867             if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) {
 868                 break;
 869             }
 870             left += Character.charCount(codepoint);
 871         }
 872         return left;
 873     }
 874 
 875     public static int lastIndexOfNonWhitespace(byte[] value) {
 876         int length = value.length >>> 1;
 877         int right = length;
 878         while (0 < right) {
 879             int codepoint = codePointBefore(value, right);
 880             if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) {
 881                 break;
 882             }
 883             right -= Character.charCount(codepoint);
 884         }
 885         return right;
 886     }
 887 
 888     public static String strip(byte[] value) {
 889         int length = value.length >>> 1;
 890         int left = indexOfNonWhitespace(value);
 891         if (left == length) {
 892             return "";
 893         }
 894         int right = lastIndexOfNonWhitespace(value);
 895         boolean ifChanged = (left > 0) || (right < length);
 896         return ifChanged ? newString(value, left, right - left) : null;
 897     }
 898 
 899     public static String stripLeading(byte[] value) {
 900         int length = value.length >>> 1;
 901         int left = indexOfNonWhitespace(value);
 902         if (left == length) {
 903             return "";
 904         }
 905         return (left != 0) ? newString(value, left, length - left) : null;
 906     }
 907 
 908     public static String stripTrailing(byte[] value) {
 909         int length = value.length >>> 1;
 910         int right = lastIndexOfNonWhitespace(value);
 911         if (right == 0) {
 912             return "";
 913         }
 914         return (right != length) ? newString(value, 0, right) : null;
 915     }
 916 
 917     private final static class LinesSpliterator implements Spliterator<String> {
 918         private byte[] value;
 919         private int index;        // current index, modified on advance/split
 920         private final int fence;  // one past last index
 921 
 922         private LinesSpliterator(byte[] value, int start, int length) {
 923             this.value = value;
 924             this.index = start;
 925             this.fence = start + length;
 926         }
 927 
 928         private int indexOfLineSeparator(int start) {
 929             for (int current = start; current < fence; current++) {
 930                 char ch = getChar(value, current);
 931                 if (ch == '\n' || ch == '\r') {
 932                     return current;
 933                 }
 934             }
 935             return fence;
 936         }
 937 
 938         private int skipLineSeparator(int start) {
 939             if (start < fence) {
 940                 if (getChar(value, start) == '\r') {
 941                     int next = start + 1;
 942                     if (next < fence && getChar(value, next) == '\n') {
 943                         return next + 1;
 944                     }
 945                 }
 946                 return start + 1;
 947             }
 948             return fence;
 949         }
 950 
 951         private String next() {
 952             int start = index;
 953             int end = indexOfLineSeparator(start);
 954             index = skipLineSeparator(end);
 955             return newString(value, start, end - start);
 956         }
 957 
 958         @Override
 959         public boolean tryAdvance(Consumer<? super String> action) {
 960             if (action == null) {
 961                 throw new NullPointerException("tryAdvance action missing");
 962             }
 963             if (index != fence) {
 964                 action.accept(next());
 965                 return true;
 966             }
 967             return false;
 968         }
 969 
 970         @Override
 971         public void forEachRemaining(Consumer<? super String> action) {
 972             if (action == null) {
 973                 throw new NullPointerException("forEachRemaining action missing");
 974             }
 975             while (index != fence) {
 976                 action.accept(next());
 977             }
 978         }
 979 
 980         @Override
 981         public Spliterator<String> trySplit() {
 982             int half = (fence + index) >>> 1;
 983             int mid = skipLineSeparator(indexOfLineSeparator(half));
 984             if (mid < fence) {
 985                 int start = index;
 986                 index = mid;
 987                 return new LinesSpliterator(value, start, mid - start);
 988             }
 989             return null;
 990         }
 991 
 992         @Override
 993         public long estimateSize() {
 994             return fence - index + 1;
 995         }
 996 
 997         @Override
 998         public int characteristics() {
 999             return Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL;
1000         }
1001 
1002         static LinesSpliterator spliterator(byte[] value) {
1003             return new LinesSpliterator(value, 0, value.length >>> 1);
1004         }
1005 
1006         static LinesSpliterator spliterator(byte[] value, int leading, int trailing) {
1007             int length = value.length >>> 1;
1008             int left = 0;
1009             int index;
1010             for (int l = 0; l < leading; l++) {
1011                 index = skipBlankForward(value, left, length);
1012                 if (index == left) {
1013                     break;
1014                 }
1015                 left = index;
1016             }
1017             int right = length;
1018             for (int t = 0; t < trailing; t++) {
1019                 index = skipBlankBackward(value, left, right);
1020                 if (index == right) {
1021                     break;
1022                 }
1023                 right = index;
1024             }
1025             return new LinesSpliterator(value, left, right - left);
1026         }
1027 
1028         private static int skipBlankForward(byte[] value, int start, int length) {
1029             int index = start;
1030             while (index < length) {
1031                 char ch = getChar(value, index++);
1032                 if (ch == '\n') {
1033                     return index;
1034                 }
1035                 if (ch == '\r') {
1036                     if (index < length && getChar(value, index) == '\n') {
1037                         return index + 1;
1038                     }
1039                     return index;
1040                 }
1041                 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) {
1042                     return start;
1043                 }
1044             }
1045             return length;
1046         }
1047 
1048         private static int skipBlankBackward(byte[] value, int start, int fence) {
1049             int index = fence;
1050             if (start < index && getChar(value, index - 1) == '\n') {
1051                 index--;
1052             }
1053             if (start < index && getChar(value, index - 1) == '\r') {
1054                 index--;
1055             }
1056             while (start < index) {
1057                 char ch = getChar(value, --index);
1058                 if (ch == '\r' || ch == '\n') {
1059                     return index + 1;
1060                 }
1061                 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) {
1062                     return fence;
1063                 }
1064             }
1065             return start;
1066         }
1067     }
1068 
1069     static Stream<String> lines(byte[] value, int leading, int trailing) {
1070         if (leading == 0 && trailing == 0) {
1071             return StreamSupport.stream(LinesSpliterator.spliterator(value), false);
1072         } else {
1073             return StreamSupport.stream(LinesSpliterator.spliterator(value, leading, trailing), false);
1074         }
1075     }
1076 
1077     private static void putChars(byte[] val, int index, char[] str, int off, int end) {
1078         while (off < end) {
1079             putChar(val, index++, str[off++]);
1080         }
1081     }
1082 
1083     public static String newString(byte[] val, int index, int len) {
1084         if (String.COMPACT_STRINGS) {
1085             byte[] buf = compress(val, index, len);
1086             if (buf != null) {
1087                 return new String(buf, LATIN1);
1088             }
1089         }
1090         int last = index + len;
1091         return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
1092     }
1093 
1094     public static void fillNull(byte[] val, int index, int end) {
1095         Arrays.fill(val, index << 1, end << 1, (byte)0);
1096     }
1097 
1098     static class CharsSpliterator implements Spliterator.OfInt {
1099         private final byte[] array;
1100         private int index;        // current index, modified on advance/split
1101         private final int fence;  // one past last index
1102         private final int cs;
1103 
1104         CharsSpliterator(byte[] array, int acs) {
1105             this(array, 0, array.length >> 1, acs);
1106         }
1107 
1108         CharsSpliterator(byte[] array, int origin, int fence, int acs) {
1109             this.array = array;
1110             this.index = origin;
1111             this.fence = fence;
1112             this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
1113                       | Spliterator.SUBSIZED;
1114         }
1115 
1116         @Override
1117         public OfInt trySplit() {
1118             int lo = index, mid = (lo + fence) >>> 1;
1119             return (lo >= mid)
1120                    ? null
1121                    : new CharsSpliterator(array, lo, index = mid, cs);
1122         }
1123 
1124         @Override
1125         public void forEachRemaining(IntConsumer action) {
1126             byte[] a; int i, hi; // hoist accesses and checks from loop
1127             if (action == null)
1128                 throw new NullPointerException();
1129             if (((a = array).length >> 1) >= (hi = fence) &&
1130                 (i = index) >= 0 && i < (index = hi)) {
1131                 do {
1132                     action.accept(charAt(a, i));
1133                 } while (++i < hi);
1134             }
1135         }
1136 
1137         @Override
1138         public boolean tryAdvance(IntConsumer action) {
1139             if (action == null)
1140                 throw new NullPointerException();
1141             int i = index;
1142             if (i >= 0 && i < fence) {
1143                 action.accept(charAt(array, i));
1144                 index++;
1145                 return true;
1146             }
1147             return false;
1148         }
1149 
1150         @Override
1151         public long estimateSize() { return (long)(fence - index); }
1152 
1153         @Override
1154         public int characteristics() {
1155             return cs;
1156         }
1157     }
1158 
1159     static class CodePointsSpliterator implements Spliterator.OfInt {
1160         private final byte[] array;
1161         private int index;        // current index, modified on advance/split
1162         private final int fence;  // one past last index
1163         private final int cs;
1164 
1165         CodePointsSpliterator(byte[] array, int acs) {
1166             this(array, 0, array.length >> 1, acs);
1167         }
1168 
1169         CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
1170             this.array = array;
1171             this.index = origin;
1172             this.fence = fence;
1173             this.cs = acs | Spliterator.ORDERED;
1174         }
1175 
1176         @Override
1177         public OfInt trySplit() {
1178             int lo = index, mid = (lo + fence) >>> 1;
1179             if (lo >= mid)
1180                 return null;
1181 
1182             int midOneLess;
1183             // If the mid-point intersects a surrogate pair
1184             if (Character.isLowSurrogate(charAt(array, mid)) &&
1185                 Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) {
1186                 // If there is only one pair it cannot be split
1187                 if (lo >= midOneLess)
1188                     return null;
1189                 // Shift the mid-point to align with the surrogate pair
1190                 return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
1191             }
1192             return new CodePointsSpliterator(array, lo, index = mid, cs);
1193         }
1194 
1195         @Override
1196         public void forEachRemaining(IntConsumer action) {
1197             byte[] a; int i, hi; // hoist accesses and checks from loop
1198             if (action == null)
1199                 throw new NullPointerException();
1200             if (((a = array).length >> 1) >= (hi = fence) &&
1201                 (i = index) >= 0 && i < (index = hi)) {
1202                 do {
1203                     i = advance(a, i, hi, action);
1204                 } while (i < hi);
1205             }
1206         }
1207 
1208         @Override
1209         public boolean tryAdvance(IntConsumer action) {
1210             if (action == null)
1211                 throw new NullPointerException();
1212             if (index >= 0 && index < fence) {
1213                 index = advance(array, index, fence, action);
1214                 return true;
1215             }
1216             return false;
1217         }
1218 
1219         // Advance one code point from the index, i, and return the next
1220         // index to advance from
1221         private static int advance(byte[] a, int i, int hi, IntConsumer action) {
1222             char c1 = charAt(a, i++);
1223             int cp = c1;
1224             if (Character.isHighSurrogate(c1) && i < hi) {
1225                 char c2 = charAt(a, i);
1226                 if (Character.isLowSurrogate(c2)) {
1227                     i++;
1228                     cp = Character.toCodePoint(c1, c2);
1229                 }
1230             }
1231             action.accept(cp);
1232             return i;
1233         }
1234 
1235         @Override
1236         public long estimateSize() { return (long)(fence - index); }
1237 
1238         @Override
1239         public int characteristics() {
1240             return cs;
1241         }
1242     }
1243 
1244     ////////////////////////////////////////////////////////////////
1245 
1246     public static void putCharSB(byte[] val, int index, int c) {
1247         checkIndex(index, val);
1248         putChar(val, index, c);
1249     }
1250 
1251     public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
1252         checkBoundsBeginEnd(index, index + end - off, val);
1253         putChars(val, index, ca, off, end);
1254     }
1255 
1256     public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
1257         checkBoundsBeginEnd(index, index + end - off, val);
1258         for (int i = off; i < end; i++) {
1259             putChar(val, index++, s.charAt(i));
1260         }
1261     }
1262 
1263     public static int codePointAtSB(byte[] val, int index, int end) {
1264         return codePointAt(val, index, end, true /* checked */);
1265     }
1266 
1267     public static int codePointBeforeSB(byte[] val, int index) {
1268         return codePointBefore(val, index, true /* checked */);
1269     }
1270 
1271     public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
1272         return codePointCount(val, beginIndex, endIndex, true /* checked */);
1273     }
1274 
1275     public static int getChars(int i, int begin, int end, byte[] value) {
1276         checkBoundsBeginEnd(begin, end, value);
1277         int pos = getChars(i, end, value);
1278         assert begin == pos;
1279         return pos;
1280     }
1281 
1282     public static int getChars(long l, int begin, int end, byte[] value) {
1283         checkBoundsBeginEnd(begin, end, value);
1284         int pos = getChars(l, end, value);
1285         assert begin == pos;
1286         return pos;
1287     }
1288 
1289     public static boolean contentEquals(byte[] v1, byte[] v2, int len) {
1290         checkBoundsOffCount(0, len, v2);
1291         for (int i = 0; i < len; i++) {
1292             if ((char)(v1[i] & 0xff) != getChar(v2, i)) {
1293                 return false;
1294             }
1295         }
1296         return true;
1297     }
1298 
1299     public static boolean contentEquals(byte[] value, CharSequence cs, int len) {
1300         checkOffset(len, value);
1301         for (int i = 0; i < len; i++) {
1302             if (getChar(value, i) != cs.charAt(i)) {
1303                 return false;
1304             }
1305         }
1306         return true;
1307     }
1308 
1309     public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) {
1310         int end = i + 4;
1311         checkBoundsBeginEnd(i, end, value);
1312         putChar(value, i++, c1);
1313         putChar(value, i++, c2);
1314         putChar(value, i++, c3);
1315         putChar(value, i++, c4);
1316         assert(i == end);
1317         return end;
1318     }
1319 
1320     public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) {
1321         int end = i + 5;
1322         checkBoundsBeginEnd(i, end, value);
1323         putChar(value, i++, c1);
1324         putChar(value, i++, c2);
1325         putChar(value, i++, c3);
1326         putChar(value, i++, c4);
1327         putChar(value, i++, c5);
1328         assert(i == end);
1329         return end;
1330     }
1331 
1332     public static char charAt(byte[] value, int index) {
1333         checkIndex(index, value);
1334         return getChar(value, index);
1335     }
1336 
1337     public static void reverse(byte[] val, int count) {
1338         checkOffset(count, val);
1339         int n = count - 1;
1340         boolean hasSurrogates = false;
1341         for (int j = (n-1) >> 1; j >= 0; j--) {
1342             int k = n - j;
1343             char cj = getChar(val, j);
1344             char ck = getChar(val, k);
1345             putChar(val, j, ck);
1346             putChar(val, k, cj);
1347             if (Character.isSurrogate(cj) ||
1348                 Character.isSurrogate(ck)) {
1349                 hasSurrogates = true;
1350             }
1351         }
1352         if (hasSurrogates) {
1353             reverseAllValidSurrogatePairs(val, count);
1354         }
1355     }
1356 
1357     /** Outlined helper method for reverse() */
1358     private static void reverseAllValidSurrogatePairs(byte[] val, int count) {
1359         for (int i = 0; i < count - 1; i++) {
1360             char c2 = getChar(val, i);
1361             if (Character.isLowSurrogate(c2)) {
1362                 char c1 = getChar(val, i + 1);
1363                 if (Character.isHighSurrogate(c1)) {
1364                     putChar(val, i++, c1);
1365                     putChar(val, i, c2);
1366                 }
1367             }
1368         }
1369     }
1370 
1371     // inflatedCopy byte[] -> byte[]
1372     public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
1373         // We need a range check here because 'putChar' has no checks
1374         checkBoundsOffCount(dstOff, len, dst);
1375         for (int i = 0; i < len; i++) {
1376             putChar(dst, dstOff++, src[srcOff++] & 0xff);
1377         }
1378     }
1379 
1380     // srcCoder == UTF16 && tgtCoder == LATIN1
1381     public static int lastIndexOfLatin1(byte[] src, int srcCount,
1382                                         byte[] tgt, int tgtCount, int fromIndex) {
1383         assert fromIndex >= 0;
1384         assert tgtCount > 0;
1385         assert tgtCount <= tgt.length;
1386         int min = tgtCount - 1;
1387         int i = min + fromIndex;
1388         int strLastIndex = tgtCount - 1;
1389 
1390         char strLastChar = (char)(tgt[strLastIndex] & 0xff);
1391 
1392         checkIndex(i, src);
1393 
1394     startSearchForLastChar:
1395         while (true) {
1396             while (i >= min && getChar(src, i) != strLastChar) {
1397                 i--;
1398             }
1399             if (i < min) {
1400                 return -1;
1401             }
1402             int j = i - 1;
1403             int start = j - strLastIndex;
1404             int k = strLastIndex - 1;
1405             while (j > start) {
1406                 if (getChar(src, j--) != (tgt[k--] & 0xff)) {
1407                     i--;
1408                     continue startSearchForLastChar;
1409                 }
1410             }
1411             return start + 1;
1412         }
1413     }
1414 
1415     ////////////////////////////////////////////////////////////////
1416 
1417     private static native boolean isBigEndian();
1418 
1419     static final int HI_BYTE_SHIFT;
1420     static final int LO_BYTE_SHIFT;
1421     static {
1422         if (isBigEndian()) {
1423             HI_BYTE_SHIFT = 8;
1424             LO_BYTE_SHIFT = 0;
1425         } else {
1426             HI_BYTE_SHIFT = 0;
1427             LO_BYTE_SHIFT = 8;
1428         }
1429     }
1430 
1431     static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
1432 
1433     // Used by trusted callers.  Assumes all necessary bounds checks have
1434     // been done by the caller.
1435 
1436     /**
1437      * This is a variant of {@link Integer#getChars(int, int, byte[])}, but for
1438      * UTF-16 coder.
1439      *
1440      * @param i     value to convert
1441      * @param index next index, after the least significant digit
1442      * @param buf   target buffer, UTF16-coded.
1443      * @return index of the most significant digit or minus sign, if present
1444      */
1445     static int getChars(int i, int index, byte[] buf) {
1446         int q, r;
1447         int charPos = index;
1448 
1449         boolean negative = (i < 0);
1450         if (!negative) {
1451             i = -i;
1452         }
1453 
1454         // Get 2 digits/iteration using ints
1455         while (i <= -100) {
1456             q = i / 100;
1457             r = (q * 100) - i;
1458             i = q;
1459             putChar(buf, --charPos, Integer.DigitOnes[r]);
1460             putChar(buf, --charPos, Integer.DigitTens[r]);
1461         }
1462 
1463         // We know there are at most two digits left at this point.
1464         q = i / 10;
1465         r = (q * 10) - i;
1466         putChar(buf, --charPos, '0' + r);
1467 
1468         // Whatever left is the remaining digit.
1469         if (q < 0) {
1470             putChar(buf, --charPos, '0' - q);
1471         }
1472 
1473         if (negative) {
1474             putChar(buf, --charPos, '-');
1475         }
1476         return charPos;
1477     }
1478 
1479     /**
1480      * This is a variant of {@link Long#getChars(long, int, byte[])}, but for
1481      * UTF-16 coder.
1482      *
1483      * @param i     value to convert
1484      * @param index next index, after the least significant digit
1485      * @param buf   target buffer, UTF16-coded.
1486      * @return index of the most significant digit or minus sign, if present
1487      */
1488     static int getChars(long i, int index, byte[] buf) {
1489         long q;
1490         int r;
1491         int charPos = index;
1492 
1493         boolean negative = (i < 0);
1494         if (!negative) {
1495             i = -i;
1496         }
1497 
1498         // Get 2 digits/iteration using longs until quotient fits into an int
1499         while (i <= Integer.MIN_VALUE) {
1500             q = i / 100;
1501             r = (int)((q * 100) - i);
1502             i = q;
1503             putChar(buf, --charPos, Integer.DigitOnes[r]);
1504             putChar(buf, --charPos, Integer.DigitTens[r]);
1505         }
1506 
1507         // Get 2 digits/iteration using ints
1508         int q2;
1509         int i2 = (int)i;
1510         while (i2 <= -100) {
1511             q2 = i2 / 100;
1512             r  = (q2 * 100) - i2;
1513             i2 = q2;
1514             putChar(buf, --charPos, Integer.DigitOnes[r]);
1515             putChar(buf, --charPos, Integer.DigitTens[r]);
1516         }
1517 
1518         // We know there are at most two digits left at this point.
1519         q2 = i2 / 10;
1520         r  = (q2 * 10) - i2;
1521         putChar(buf, --charPos, '0' + r);
1522 
1523         // Whatever left is the remaining digit.
1524         if (q2 < 0) {
1525             putChar(buf, --charPos, '0' - q2);
1526         }
1527 
1528         if (negative) {
1529             putChar(buf, --charPos, '-');
1530         }
1531         return charPos;
1532     }
1533     // End of trusted methods.
1534 
1535     public static void checkIndex(int off, byte[] val) {
1536         String.checkIndex(off, length(val));
1537     }
1538 
1539     public static void checkOffset(int off, byte[] val) {
1540         String.checkOffset(off, length(val));
1541     }
1542 
1543     public static void checkBoundsBeginEnd(int begin, int end, byte[] val) {
1544         String.checkBoundsBeginEnd(begin, end, length(val));
1545     }
1546 
1547     public static void checkBoundsOffCount(int offset, int count, byte[] val) {
1548         String.checkBoundsOffCount(offset, count, length(val));
1549     }
1550 
1551 }