1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang;
  27 
  28 import java.util.Arrays;
  29 import java.util.Locale;
  30 import java.util.Spliterator;
  31 import java.util.function.IntConsumer;
  32 import jdk.internal.HotSpotIntrinsicCandidate;
  33 import jdk.internal.vm.annotation.ForceInline;
  34 import jdk.internal.vm.annotation.DontInline;
  35 
  36 import static java.lang.String.UTF16;
  37 import static java.lang.String.LATIN1;
  38 //import static java.lang.String.checkIndex;
  39 //import static java.lang.String.checkOffset;
  40 //import static java.lang.String.checkBoundsOffCount;
  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     // should be private but then javac generates an accessor method
  57     // intrinsic performs no bounds checks
  58     static void putCharUnsafe(byte[] val, int index, int c) {
  59         index <<= 1;
  60         val[index++] = (byte)(c >> HI_BYTE_SHIFT);
  61         val[index]   = (byte)(c >> LO_BYTE_SHIFT);
  62     }
  63 
  64     @HotSpotIntrinsicCandidate
  65     // should be private but then javac generates an accessor method
  66     // intrinsic performs no bounds checks
  67     static char getCharUnsafe(byte[] val, int index) {
  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 = Trusted.getChar(value, index);
  83         if (Character.isHighSurrogate(c1) && ++index < end) {
  84             if (checked) {
  85                 checkIndex(index, value);
  86             }
  87             char c2 = Trusted.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 = Trusted.getChar(value, index);
 105         if (Character.isLowSurrogate(c2) && index > 0) {
 106             --index;
 107             if (checked) {
 108                 checkIndex(index, value);
 109             }
 110             char c1 = Trusted.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(Trusted.getChar(value, i++)) &&
 131                 Character.isLowSurrogate(Trusted.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             Trusted.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 = Trusted.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                 Trusted.putChar(buf, j, cp);
 227             } else {
 228                 Trusted.putChar(buf, j++, Character.highSurrogate(cp));
 229                 Trusted.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         Trusted.putChar(result, 0, c);
 238         return result;
 239     }
 240 
 241     @HotSpotIntrinsicCandidate
 242     public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
 243         // We need a range check here because 'getChar' has no checks
 244         if (srcBegin < srcEnd) {
 245             checkBoundsOffCount(srcBegin, srcEnd - srcBegin, value);
 246         }
 247         for (int i = srcBegin; i < srcEnd; i++) {
 248             dst[dstBegin++] = Trusted.getChar(value, i);
 249         }
 250     }
 251 
 252     /* @see java.lang.String.getBytes(int, int, byte[], int) */
 253     public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
 254         srcBegin <<= 1;
 255         srcEnd <<= 1;
 256         for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) {
 257             dst[dstBegin++] = value[i];
 258         }
 259     }
 260 
 261     @HotSpotIntrinsicCandidate
 262     public static boolean equals(byte[] value, byte[] other) {
 263         if (value.length == other.length) {
 264             int len = value.length >> 1;
 265             for (int i = 0; i < len; i++) {
 266                 if (Trusted.getChar(value, i) != Trusted.getChar(other, i)) {
 267                     return false;
 268                 }
 269             }
 270             return true;
 271         }
 272         return false;
 273     }
 274 
 275     @HotSpotIntrinsicCandidate
 276     public static int compareTo(byte[] value, byte[] other) {
 277         int len1 = length(value);
 278         int len2 = length(other);
 279         int lim = Math.min(len1, len2);
 280         for (int k = 0; k < lim; k++) {
 281             char c1 = Trusted.getChar(value, k);
 282             char c2 = Trusted.getChar(other, k);
 283             if (c1 != c2) {
 284                 return c1 - c2;
 285             }
 286         }
 287         return len1 - len2;
 288     }
 289 
 290     @HotSpotIntrinsicCandidate
 291     public static int compareToLatin1(byte[] value, byte[] other) {
 292         return -StringLatin1.compareToUTF16(other, value);
 293     }
 294 
 295     public static int compareToCI(byte[] value, byte[] other) {
 296         int len1 = length(value);
 297         int len2 = length(other);
 298         int lim = Math.min(len1, len2);
 299         for (int k = 0; k < lim; k++) {
 300             char c1 = Trusted.getChar(value, k);
 301             char c2 = Trusted.getChar(other, k);
 302             if (c1 != c2) {
 303                 c1 = Character.toUpperCase(c1);
 304                 c2 = Character.toUpperCase(c2);
 305                 if (c1 != c2) {
 306                     c1 = Character.toLowerCase(c1);
 307                     c2 = Character.toLowerCase(c2);
 308                     if (c1 != c2) {
 309                         return c1 - c2;
 310                     }
 311                 }
 312             }
 313         }
 314         return len1 - len2;
 315     }
 316 
 317     public static int compareToCI_Latin1(byte[] value, byte[] other) {
 318         return -StringLatin1.compareToCI_UTF16(other, value);
 319     }
 320 
 321     public static int hashCode(byte[] value) {
 322         int h = 0;
 323         int length = value.length >> 1;
 324         for (int i = 0; i < length; i++) {
 325             h = 31 * h + Trusted.getChar(value, i);
 326         }
 327         return h;
 328     }
 329 
 330     public static int indexOf(byte[] value, int ch, int fromIndex) {
 331         int max = value.length >> 1;
 332         if (fromIndex < 0) {
 333             fromIndex = 0;
 334         } else if (fromIndex >= max) {
 335             // Note: fromIndex might be near -1>>>1.
 336             return -1;
 337         }
 338         if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
 339             // handle most cases here (ch is a BMP code point or a
 340             // negative value (invalid code point))
 341             return indexOfChar(value, ch, fromIndex, max);
 342         } else {
 343             return indexOfSupplementary(value, ch, fromIndex, max);
 344         }
 345     }
 346 
 347     @HotSpotIntrinsicCandidate
 348     public static int indexOf(byte[] value, byte[] str) {
 349         if (str.length == 0) {
 350             return 0;
 351         }
 352         if (value.length < str.length) {
 353             return -1;
 354         }
 355         return indexOfUnsafe(value, length(value), str, length(str), 0);
 356     }
 357 
 358     @HotSpotIntrinsicCandidate
 359     public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
 360         checkBoundsBeginEnd(fromIndex, valueCount, value);
 361         checkBoundsBeginEnd(0, strCount, str);
 362         return indexOfUnsafe(value, valueCount, str, strCount, fromIndex);
 363     }
 364 
 365 
 366     private static int indexOfUnsafe(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
 367         assert fromIndex >= 0;
 368         assert strCount > 0;
 369         assert strCount <= length(str);
 370         assert valueCount >= strCount;
 371         char first = Trusted.getChar(str, 0);
 372         int max = (valueCount - strCount);
 373         for (int i = fromIndex; i <= max; i++) {
 374             // Look for first character.
 375             if (Trusted.getChar(value, i) != first) {
 376                 while (++i <= max && Trusted.getChar(value, i) != first);
 377             }
 378             // Found first character, now look at the rest of value
 379             if (i <= max) {
 380                 int j = i + 1;
 381                 int end = j + strCount - 1;
 382                 for (int k = 1; j < end && Trusted.getChar(value, j) == Trusted.getChar(str, k); j++, k++);
 383                 if (j == end) {
 384                     // Found whole string.
 385                     return i;
 386                 }
 387             }
 388         }
 389         return -1;
 390     }
 391 
 392 
 393     /**
 394      * Handles indexOf Latin1 substring in UTF16 string.
 395      */
 396     @HotSpotIntrinsicCandidate
 397     public static int indexOfLatin1(byte[] value, byte[] str) {
 398         if (str.length == 0) {
 399             return 0;
 400         }
 401         if (length(value) < str.length) {
 402             return -1;
 403         }
 404         return indexOfLatin1Unsafe(value, length(value), str, str.length, 0);
 405     }
 406 
 407     @HotSpotIntrinsicCandidate
 408     public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
 409         checkBoundsBeginEnd(fromIndex, srcCount, src);
 410         String.checkBoundsBeginEnd(0, tgtCount, tgt.length);
 411         return indexOfLatin1Unsafe(src, srcCount, tgt, tgtCount, fromIndex);
 412     }
 413 
 414     public static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
 415         assert fromIndex >= 0;
 416         assert tgtCount > 0;
 417         assert tgtCount <= tgt.length;
 418         assert srcCount >= tgtCount;
 419         char first = (char)(tgt[0] & 0xff);
 420         int max = (srcCount - tgtCount);
 421         for (int i = fromIndex; i <= max; i++) {
 422             // Look for first character.
 423             if (Trusted.getChar(src, i) != first) {
 424                 while (++i <= max && Trusted.getChar(src, i) != first);
 425             }
 426             // Found first character, now look at the rest of v2
 427             if (i <= max) {
 428                 int j = i + 1;
 429                 int end = j + tgtCount - 1;
 430                 for (int k = 1;
 431                      j < end && Trusted.getChar(src, j) == (tgt[k] & 0xff);
 432                      j++, k++);
 433                 if (j == end) {
 434                     // Found whole string.
 435                     return i;
 436                 }
 437             }
 438         }
 439         return -1;
 440     }
 441 
 442     @HotSpotIntrinsicCandidate
 443     private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) {
 444         checkBoundsBeginEnd(fromIndex, max, value);
 445         return indexOfCharUnsafe(value, ch, fromIndex, max);
 446     }
 447 
 448     private static int indexOfCharUnsafe(byte[] value, int ch, int fromIndex, int max) {
 449         for (int i = fromIndex; i < max; i++) {
 450             if (Trusted.getChar(value, i) == ch) {
 451                 return i;
 452             }
 453         }
 454         return -1;
 455     }
 456 
 457     /**
 458      * Handles (rare) calls of indexOf with a supplementary character.
 459      */
 460     private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) {
 461         if (Character.isValidCodePoint(ch)) {
 462             final char hi = Character.highSurrogate(ch);
 463             final char lo = Character.lowSurrogate(ch);
 464             checkBoundsBeginEnd(fromIndex, max, value);
 465             for (int i = fromIndex; i < max - 1; i++) {
 466                 if (Trusted.getChar(value, i) == hi && Trusted.getChar(value, i + 1 ) == lo) {
 467                     return i;
 468                 }
 469             }
 470         }
 471         return -1;
 472     }
 473 
 474     // srcCoder == UTF16 && tgtCoder == UTF16
 475     public static int lastIndexOf(byte[] src, int srcCount,
 476                                   byte[] tgt, int tgtCount, int fromIndex) {
 477         assert fromIndex >= 0;
 478         assert tgtCount > 0;
 479         assert tgtCount <= length(tgt);
 480         int min = tgtCount - 1;
 481         int i = min + fromIndex;
 482         int strLastIndex = tgtCount - 1;
 483 
 484         checkIndex(strLastIndex, tgt);
 485         char strLastChar = Trusted.getChar(tgt, strLastIndex);
 486 
 487         checkIndex(i, src);
 488 
 489     startSearchForLastChar:
 490         while (true) {
 491             while (i >= min && Trusted.getChar(src, i) != strLastChar) {
 492                 i--;
 493             }
 494             if (i < min) {
 495                 return -1;
 496             }
 497             int j = i - 1;
 498             int start = j - strLastIndex;
 499             int k = strLastIndex - 1;
 500             while (j > start) {
 501                 if (Trusted.getChar(src, j--) != Trusted.getChar(tgt, k--)) {
 502                     i--;
 503                     continue startSearchForLastChar;
 504                 }
 505             }
 506             return start + 1;
 507         }
 508     }
 509 
 510     public static int lastIndexOf(byte[] value, int ch, int fromIndex) {
 511         if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
 512             // handle most cases here (ch is a BMP code point or a
 513             // negative value (invalid code point))
 514             int i = Math.min(fromIndex, (value.length >> 1) - 1);
 515             for (; i >= 0; i--) {
 516                 if (Trusted.getChar(value, i) == ch) {
 517                     return i;
 518                 }
 519             }
 520             return -1;
 521         } else {
 522             return lastIndexOfSupplementary(value, ch, fromIndex);
 523         }
 524     }
 525 
 526     /**
 527      * Handles (rare) calls of lastIndexOf with a supplementary character.
 528      */
 529     private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) {
 530         if (Character.isValidCodePoint(ch)) {
 531             char hi = Character.highSurrogate(ch);
 532             char lo = Character.lowSurrogate(ch);
 533             int i = Math.min(fromIndex, (value.length >> 1) - 2);
 534             for (; i >= 0; i--) {
 535                 if (Trusted.getChar(value, i) == hi && Trusted.getChar(value, i + 1) == lo) {
 536                     return i;
 537                 }
 538             }
 539         }
 540         return -1;
 541     }
 542 
 543     public static String replace(byte[] value, char oldChar, char newChar) {
 544         int len = value.length >> 1;
 545         int i = -1;
 546         while (++i < len) {
 547             if (Trusted.getChar(value, i) == oldChar) {
 548                 break;
 549             }
 550         }
 551         if (i < len) {
 552             byte buf[] = new byte[value.length];
 553             for (int j = 0; j < i; j++) {
 554                 Trusted.putChar(buf, j, Trusted.getChar(value, j)); // TBD:arraycopy?
 555             }
 556             while (i < len) {
 557                 char c = Trusted.getChar(value, i);
 558                 Trusted.putChar(buf, i, c == oldChar ? newChar : c);
 559                 i++;
 560            }
 561            // Check if we should try to compress to latin1
 562            if (String.COMPACT_STRINGS &&
 563                !StringLatin1.canEncode(oldChar) &&
 564                StringLatin1.canEncode(newChar)) {
 565                byte[] val = compress(buf, 0, len);
 566                if (val != null) {
 567                    return new String(val, LATIN1);
 568                }
 569            }
 570            return new String(buf, UTF16);
 571         }
 572         return null;
 573     }
 574 
 575     public static boolean regionMatchesCI(byte[] value, int toffset,
 576                                           byte[] other, int ooffset, int len) {
 577         int last = toffset + len;
 578         assert toffset >= 0 && ooffset >= 0;
 579         assert ooffset + len <= length(other);
 580         assert last <= length(value);
 581         while (toffset < last) {
 582             char c1 = Trusted.getChar(value, toffset++);
 583             char c2 = Trusted.getChar(other, ooffset++);
 584             if (c1 == c2) {
 585                 continue;
 586             }
 587             // try converting both characters to uppercase.
 588             // If the results match, then the comparison scan should
 589             // continue.
 590             char u1 = Character.toUpperCase(c1);
 591             char u2 = Character.toUpperCase(c2);
 592             if (u1 == u2) {
 593                 continue;
 594             }
 595             // Unfortunately, conversion to uppercase does not work properly
 596             // for the Georgian alphabet, which has strange rules about case
 597             // conversion.  So we need to make one last check before
 598             // exiting.
 599             if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
 600                 continue;
 601             }
 602             return false;
 603         }
 604         return true;
 605     }
 606 
 607     public static boolean regionMatchesCI_Latin1(byte[] value, int toffset,
 608                                                  byte[] other, int ooffset,
 609                                                  int len) {
 610         return StringLatin1.regionMatchesCI_UTF16(other, ooffset, value, toffset, len);
 611     }
 612 
 613     public static String toLowerCase(String str, byte[] value, Locale locale) {
 614         if (locale == null) {
 615             throw new NullPointerException();
 616         }
 617         int first;
 618         boolean hasSurr = false;
 619         final int len = value.length >> 1;
 620 
 621         // Now check if there are any characters that need to be changed, or are surrogate
 622         for (first = 0 ; first < len; first++) {
 623             int cp = (int)Trusted.getChar(value, first);
 624             if (Character.isSurrogate((char)cp)) {
 625                 hasSurr = true;
 626                 break;
 627             }
 628             if (cp != Character.toLowerCase(cp)) {  // no need to check Character.ERROR
 629                 break;
 630             }
 631         }
 632         if (first == len)
 633             return str;
 634         byte[] result = new byte[value.length];
 635         System.arraycopy(value, 0, result, 0, first << 1);  // Just copy the first few
 636                                                             // lowerCase characters.
 637         String lang = locale.getLanguage();
 638         if (lang == "tr" || lang == "az" || lang == "lt") {
 639             return toLowerCaseEx(str, value, result, first, locale, true);
 640         }
 641         if (hasSurr) {
 642             return toLowerCaseEx(str, value, result, first, locale, false);
 643         }
 644         int bits = 0;
 645         for (int i = first; i < len; i++) {
 646             int cp = (int)Trusted.getChar(value, i);
 647             if (cp == '\u03A3' ||                       // GREEK CAPITAL LETTER SIGMA
 648                 Character.isSurrogate((char)cp)) {
 649                 return toLowerCaseEx(str, value, result, i, locale, false);
 650             }
 651             if (cp == '\u0130') {                       // LATIN CAPITAL LETTER I WITH DOT ABOVE
 652                 return toLowerCaseEx(str, value, result, i, locale, true);
 653             }
 654             cp = Character.toLowerCase(cp);
 655             if (!Character.isBmpCodePoint(cp)) {
 656                 return toLowerCaseEx(str, value, result, i, locale, false);
 657             }
 658             bits |= cp;
 659             Trusted.putChar(result, i, cp);
 660         }
 661         if (bits > 0xFF) {
 662             return new String(result, UTF16);
 663         } else {
 664             return newString(result, 0, len);
 665         }
 666     }
 667 
 668     private static String toLowerCaseEx(String str, byte[] value,
 669                                         byte[] result, int first, Locale locale,
 670                                         boolean localeDependent) {
 671         assert(result.length == value.length);
 672         assert(first >= 0);
 673         int resultOffset = first;
 674         int length = value.length >> 1;
 675         int srcCount;
 676         for (int i = first; i < length; i += srcCount) {
 677             int srcChar = Trusted.getChar(value, i);
 678             int lowerChar;
 679             char[] lowerCharArray;
 680             srcCount = 1;
 681             if (Character.isSurrogate((char)srcChar)) {
 682                 srcChar = codePointAt(value, i, length);
 683                 srcCount = Character.charCount(srcChar);
 684             }
 685             if (localeDependent ||
 686                 srcChar == '\u03A3' ||  // GREEK CAPITAL LETTER SIGMA
 687                 srcChar == '\u0130') {  // LATIN CAPITAL LETTER I WITH DOT ABOVE
 688                 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
 689             } else {
 690                 lowerChar = Character.toLowerCase(srcChar);
 691             }
 692             if (Character.isBmpCodePoint(lowerChar)) {    // Character.ERROR is not a bmp
 693                 Trusted.putChar(result, resultOffset++, lowerChar);
 694             } else {
 695                 if (lowerChar == Character.ERROR) {
 696                     lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
 697                 } else {
 698                     lowerCharArray = Character.toChars(lowerChar);
 699                 }
 700                 /* Grow result if needed */
 701                 int mapLen = lowerCharArray.length;
 702                 if (mapLen > srcCount) {
 703                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 704                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 705                     result = result2;
 706                 }
 707                 assert resultOffset >= 0;
 708                 assert resultOffset + mapLen <= length(result);
 709                 for (int x = 0; x < mapLen; ++x) {
 710                     Trusted.putChar(result, resultOffset++, lowerCharArray[x]);
 711                 }
 712             }
 713         }
 714         return newString(result, 0, resultOffset);
 715     }
 716 
 717     public static String toUpperCase(String str, byte[] value, Locale locale) {
 718         if (locale == null) {
 719             throw new NullPointerException();
 720         }
 721         int first;
 722         boolean hasSurr = false;
 723         final int len = value.length >> 1;
 724 
 725         // Now check if there are any characters that need to be changed, or are surrogate
 726         for (first = 0 ; first < len; first++) {
 727             int cp = (int)Trusted.getChar(value, first);
 728             if (Character.isSurrogate((char)cp)) {
 729                 hasSurr = true;
 730                 break;
 731             }
 732             if (cp != Character.toUpperCaseEx(cp)) {   // no need to check Character.ERROR
 733                 break;
 734             }
 735         }
 736         if (first == len) {
 737             return str;
 738         }
 739         byte[] result = new byte[value.length];
 740         System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
 741                                                            // upperCase characters.
 742         String lang = locale.getLanguage();
 743         if (lang == "tr" || lang == "az" || lang == "lt") {
 744             return toUpperCaseEx(str, value, result, first, locale, true);
 745         }
 746         if (hasSurr) {
 747             return toUpperCaseEx(str, value, result, first, locale, false);
 748         }
 749         int bits = 0;
 750         for (int i = first; i < len; i++) {
 751             int cp = (int)Trusted.getChar(value, i);
 752             if (Character.isSurrogate((char)cp)) {
 753                 return toUpperCaseEx(str, value, result, i, locale, false);
 754             }
 755             cp = Character.toUpperCaseEx(cp);
 756             if (!Character.isBmpCodePoint(cp)) {    // Character.ERROR is not bmp
 757                 return toUpperCaseEx(str, value, result, i, locale, false);
 758             }
 759             bits |= cp;
 760             Trusted.putChar(result, i, cp);
 761         }
 762         if (bits > 0xFF) {
 763             return new String(result, UTF16);
 764         } else {
 765             return newString(result, 0, len);
 766         }
 767     }
 768 
 769     private static String toUpperCaseEx(String str, byte[] value,
 770                                         byte[] result, int first,
 771                                         Locale locale, boolean localeDependent)
 772     {
 773         assert(result.length == value.length);
 774         assert(first >= 0);
 775         int resultOffset = first;
 776         int length = value.length >> 1;
 777         int srcCount;
 778         for (int i = first; i < length; i += srcCount) {
 779             int srcChar = Trusted.getChar(value, i);
 780             int upperChar;
 781             char[] upperCharArray;
 782             srcCount = 1;
 783             if (Character.isSurrogate((char)srcChar)) {
 784                 srcChar = codePointAt(value, i, length);
 785                 srcCount = Character.charCount(srcChar);
 786             }
 787             if (localeDependent) {
 788                 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
 789             } else {
 790                 upperChar = Character.toUpperCaseEx(srcChar);
 791             }
 792             if (Character.isBmpCodePoint(upperChar)) {
 793                 Trusted.putChar(result, resultOffset++, upperChar);
 794             } else {
 795                 if (upperChar == Character.ERROR) {
 796                     if (localeDependent) {
 797                         upperCharArray =
 798                             ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
 799                     } else {
 800                         upperCharArray = Character.toUpperCaseCharArray(srcChar);
 801                     }
 802                 } else {
 803                     upperCharArray = Character.toChars(upperChar);
 804                 }
 805                 /* Grow result if needed */
 806                 int mapLen = upperCharArray.length;
 807                 if (mapLen > srcCount) {
 808                     byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
 809                     System.arraycopy(result, 0, result2, 0, resultOffset << 1);
 810                     result = result2;
 811                 }
 812                 assert resultOffset >= 0;
 813                 assert resultOffset + mapLen <= length(result);
 814                 for (int x = 0; x < mapLen; ++x) {
 815                     Trusted.putChar(result, resultOffset++, upperCharArray[x]);
 816                 }
 817             }
 818         }
 819         return newString(result, 0, resultOffset);
 820     }
 821 
 822     public static String trim(byte[] value) {
 823         int length = value.length >> 1;
 824         int len = length;
 825         int st = 0;
 826         while (st < len && Trusted.getChar(value, st) <= ' ') {
 827             st++;
 828         }
 829         while (st < len && Trusted.getChar(value, len - 1) <= ' ') {
 830             len--;
 831         }
 832         return ((st > 0) || (len < length )) ?
 833             new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) :
 834             null;
 835     }
 836 
 837     private static void putChars(byte[] val, int index, char[] str, int off, int end) {
 838         while (off < end) {
 839             Trusted.putChar(val, index++, str[off++]);
 840         }
 841     }
 842 
 843     public static String newString(byte[] val, int index, int len) {
 844         if (String.COMPACT_STRINGS) {
 845             byte[] buf = compress(val, index, len);
 846             if (buf != null) {
 847                 return new String(buf, LATIN1);
 848             }
 849         }
 850         int last = index + len;
 851         return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
 852     }
 853 
 854     public static void fillNull(byte[] val, int index, int end) {
 855         Arrays.fill(val, index << 1, end << 1, (byte)0);
 856     }
 857 
 858     static class CharsSpliterator implements Spliterator.OfInt {
 859         private final byte[] array;
 860         private int index;        // current index, modified on advance/split
 861         private final int fence;  // one past last index
 862         private final int cs;
 863 
 864         CharsSpliterator(byte[] array, int acs) {
 865             this(array, 0, array.length >> 1, acs);
 866         }
 867 
 868         CharsSpliterator(byte[] array, int origin, int fence, int acs) {
 869             this.array = array;
 870             this.index = origin;
 871             this.fence = fence;
 872             this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
 873                       | Spliterator.SUBSIZED;
 874         }
 875 
 876         @Override
 877         public OfInt trySplit() {
 878             int lo = index, mid = (lo + fence) >>> 1;
 879             return (lo >= mid)
 880                    ? null
 881                    : new CharsSpliterator(array, lo, index = mid, cs);
 882         }
 883 
 884         @Override
 885         public void forEachRemaining(IntConsumer action) {
 886             byte[] a; int i, hi; // hoist accesses and checks from loop
 887             if (action == null)
 888                 throw new NullPointerException();
 889             if (((a = array).length >> 1) >= (hi = fence) &&
 890                 (i = index) >= 0 && i < (index = hi)) {
 891                 do {
 892                     action.accept(charAt(a, i));
 893                 } while (++i < hi);
 894             }
 895         }
 896 
 897         @Override
 898         public boolean tryAdvance(IntConsumer action) {
 899             if (action == null)
 900                 throw new NullPointerException();
 901             int i = index;
 902             if (i >= 0 && i < fence) {
 903                 action.accept(charAt(array, i));
 904                 index++;
 905                 return true;
 906             }
 907             return false;
 908         }
 909 
 910         @Override
 911         public long estimateSize() { return (long)(fence - index); }
 912 
 913         @Override
 914         public int characteristics() {
 915             return cs;
 916         }
 917     }
 918 
 919     static class CodePointsSpliterator implements Spliterator.OfInt {
 920         private final byte[] array;
 921         private int index;        // current index, modified on advance/split
 922         private final int fence;  // one past last index
 923         private final int cs;
 924 
 925         CodePointsSpliterator(byte[] array, int acs) {
 926             this(array, 0, array.length >> 1, acs);
 927         }
 928 
 929         CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
 930             this.array = array;
 931             this.index = origin;
 932             this.fence = fence;
 933             this.cs = acs | Spliterator.ORDERED;
 934         }
 935 
 936         @Override
 937         public OfInt trySplit() {
 938             int lo = index, mid = (lo + fence) >>> 1;
 939             if (lo >= mid)
 940                 return null;
 941 
 942             int midOneLess;
 943             // If the mid-point intersects a surrogate pair
 944             if (Character.isLowSurrogate(charAt(array, mid)) &&
 945                 Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) {
 946                 // If there is only one pair it cannot be split
 947                 if (lo >= midOneLess)
 948                     return null;
 949                 // Shift the mid-point to align with the surrogate pair
 950                 return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
 951             }
 952             return new CodePointsSpliterator(array, lo, index = mid, cs);
 953         }
 954 
 955         @Override
 956         public void forEachRemaining(IntConsumer action) {
 957             byte[] a; int i, hi; // hoist accesses and checks from loop
 958             if (action == null)
 959                 throw new NullPointerException();
 960             if (((a = array).length >> 1) >= (hi = fence) &&
 961                 (i = index) >= 0 && i < (index = hi)) {
 962                 do {
 963                     i = advance(a, i, hi, action);
 964                 } while (i < hi);
 965             }
 966         }
 967 
 968         @Override
 969         public boolean tryAdvance(IntConsumer action) {
 970             if (action == null)
 971                 throw new NullPointerException();
 972             if (index >= 0 && index < fence) {
 973                 index = advance(array, index, fence, action);
 974                 return true;
 975             }
 976             return false;
 977         }
 978 
 979         // Advance one code point from the index, i, and return the next
 980         // index to advance from
 981         private static int advance(byte[] a, int i, int hi, IntConsumer action) {
 982             char c1 = charAt(a, i++);
 983             int cp = c1;
 984             if (Character.isHighSurrogate(c1) && i < hi) {
 985                 char c2 = charAt(a, i);
 986                 if (Character.isLowSurrogate(c2)) {
 987                     i++;
 988                     cp = Character.toCodePoint(c1, c2);
 989                 }
 990             }
 991             action.accept(cp);
 992             return i;
 993         }
 994 
 995         @Override
 996         public long estimateSize() { return (long)(fence - index); }
 997 
 998         @Override
 999         public int characteristics() {
1000             return cs;
1001         }
1002     }
1003 
1004     ////////////////////////////////////////////////////////////////
1005 
1006     public static void putCharSB(byte[] val, int index, int c) {
1007         checkIndex(index, val);
1008         Trusted.putChar(val, index, c);
1009     }
1010 
1011     public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
1012         checkBoundsBeginEnd(index, index + end - off, val);
1013         putChars(val, index, ca, off, end);
1014     }
1015 
1016     public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
1017         checkBoundsBeginEnd(index, index + end - off, val);
1018         for (int i = off; i < end; i++) {
1019             Trusted.putChar(val, index++, s.charAt(i));
1020         }
1021     }
1022 
1023     public static int codePointAtSB(byte[] val, int index, int end) {
1024         return codePointAt(val, index, end, true /* checked */);
1025     }
1026 
1027     public static int codePointBeforeSB(byte[] val, int index) {
1028         return codePointBefore(val, index, true /* checked */);
1029     }
1030 
1031     public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
1032         return codePointCount(val, beginIndex, endIndex, true /* checked */);
1033     }
1034 
1035     public static int getChars(int i, int begin, int end, byte[] value) {
1036         checkBoundsBeginEnd(begin, end, value);
1037         int pos = Trusted.getChars(i, end, value);
1038         assert begin == pos;
1039         return pos;
1040     }
1041 
1042     public static int getChars(long l, int begin, int end, byte[] value) {
1043         checkBoundsBeginEnd(begin, end, value);
1044         int pos = Trusted.getChars(l, end, value);
1045         assert begin == pos;
1046         return pos;
1047     }
1048 
1049     public static boolean contentEquals(byte[] v1, byte[] v2, int len) {
1050         checkBoundsOffCount(0, len, v2);
1051         for (int i = 0; i < len; i++) {
1052             if ((char)(v1[i] & 0xff) != Trusted.getChar(v2, i)) {
1053                 return false;
1054             }
1055         }
1056         return true;
1057     }
1058 
1059     public static boolean contentEquals(byte[] value, CharSequence cs, int len) {
1060         checkOffset(len, value);
1061         for (int i = 0; i < len; i++) {
1062             if (Trusted.getChar(value, i) != cs.charAt(i)) {
1063                 return false;
1064             }
1065         }
1066         return true;
1067     }
1068 
1069     public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) {
1070         int end = i + 4;
1071         checkBoundsBeginEnd(i, end, value);
1072         Trusted.putChar(value, i++, c1);
1073         Trusted.putChar(value, i++, c2);
1074         Trusted.putChar(value, i++, c3);
1075         Trusted.putChar(value, i++, c4);
1076         assert(i == end);
1077         return end;
1078     }
1079 
1080     public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) {
1081         int end = i + 5;
1082         checkBoundsBeginEnd(i, end, value);
1083         Trusted.putChar(value, i++, c1);
1084         Trusted.putChar(value, i++, c2);
1085         Trusted.putChar(value, i++, c3);
1086         Trusted.putChar(value, i++, c4);
1087         Trusted.putChar(value, i++, c5);
1088         assert(i == end);
1089         return end;
1090     }
1091 
1092     public static char charAt(byte[] value, int index) {
1093         checkIndex(index, value);
1094         return Trusted.getChar(value, index);
1095     }
1096 
1097     public static void reverse(byte[] val, int count) {
1098         checkOffset(count, val);
1099         int n = count - 1;
1100         boolean hasSurrogates = false;
1101         for (int j = (n-1) >> 1; j >= 0; j--) {
1102             int k = n - j;
1103             char cj = Trusted.getChar(val, j);
1104             char ck = Trusted.getChar(val, k);
1105             Trusted.putChar(val, j, ck);
1106             Trusted.putChar(val, k, cj);
1107             if (Character.isSurrogate(cj) ||
1108                 Character.isSurrogate(ck)) {
1109                 hasSurrogates = true;
1110             }
1111         }
1112         if (hasSurrogates) {
1113             reverseAllValidSurrogatePairs(val, count);
1114         }
1115     }
1116 
1117     /** Outlined helper method for reverse() */
1118     private static void reverseAllValidSurrogatePairs(byte[] val, int count) {
1119         for (int i = 0; i < count - 1; i++) {
1120             char c2 = Trusted.getChar(val, i);
1121             if (Character.isLowSurrogate(c2)) {
1122                 char c1 = Trusted.getChar(val, i + 1);
1123                 if (Character.isHighSurrogate(c1)) {
1124                     Trusted.putChar(val, i++, c1);
1125                     Trusted.putChar(val, i, c2);
1126                 }
1127             }
1128         }
1129     }
1130 
1131     // inflatedCopy byte[] -> byte[]
1132     public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
1133         // We need a range check here because 'putChar' has no checks
1134         checkBoundsOffCount(dstOff, len, dst);
1135         for (int i = 0; i < len; i++) {
1136             Trusted.putChar(dst, dstOff++, src[srcOff++] & 0xff);
1137         }
1138     }
1139 
1140     // srcCoder == UTF16 && tgtCoder == LATIN1
1141     public static int lastIndexOfLatin1(byte[] src, int srcCount,
1142                                         byte[] tgt, int tgtCount, int fromIndex) {
1143         assert fromIndex >= 0;
1144         assert tgtCount > 0;
1145         assert tgtCount <= tgt.length;
1146         int min = tgtCount - 1;
1147         int i = min + fromIndex;
1148         int strLastIndex = tgtCount - 1;
1149 
1150         char strLastChar = (char)(tgt[strLastIndex] & 0xff);
1151 
1152         checkIndex(i, src);
1153 
1154     startSearchForLastChar:
1155         while (true) {
1156             while (i >= min && Trusted.getChar(src, i) != strLastChar) {
1157                 i--;
1158             }
1159             if (i < min) {
1160                 return -1;
1161             }
1162             int j = i - 1;
1163             int start = j - strLastIndex;
1164             int k = strLastIndex - 1;
1165             while (j > start) {
1166                 if (Trusted.getChar(src, j--) != (tgt[k--] & 0xff)) {
1167                     i--;
1168                     continue startSearchForLastChar;
1169                 }
1170             }
1171             return start + 1;
1172         }
1173     }
1174 
1175     ////////////////////////////////////////////////////////////////
1176 
1177     private static native boolean isBigEndian();
1178 
1179     static final int HI_BYTE_SHIFT;
1180     static final int LO_BYTE_SHIFT;
1181     static {
1182         if (isBigEndian()) {
1183             HI_BYTE_SHIFT = 8;
1184             LO_BYTE_SHIFT = 0;
1185         } else {
1186             HI_BYTE_SHIFT = 0;
1187             LO_BYTE_SHIFT = 8;
1188         }
1189     }
1190 
1191     static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
1192 
1193     @DontInline
1194     static char throwAssertionError(Throwable e) {
1195         throw new AssertionError("Trusted caller missed bounds check", e);
1196     }
1197 
1198     @DontInline
1199     static AssertionError assertionError(Throwable e) {
1200         return new AssertionError("Trusted caller missed bounds check", e);
1201     }
1202 
1203     // Used by trusted callers.  Assumes all necessary bounds checks have
1204     // been done by the caller.
1205     static class Trusted {
1206 
1207         @ForceInline
1208         static char getChar(byte[] val, int index) {
1209             assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
1210             if (!String.DEBUG_INTRINSICS) {
1211                 return getCharUnsafe(val, index);
1212             }
1213             try {
1214                 return getCharUnsafe(val, index);
1215             } catch (IndexOutOfBoundsException e) {
1216                 return throwAssertionError(e);
1217             }
1218         }
1219 
1220         @ForceInline
1221         static void putChar(byte[] val, int index, int c) {
1222             assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
1223             if (!String.DEBUG_INTRINSICS) {
1224                 putCharUnsafe(val, index, c);
1225                 return;
1226             }
1227             try {
1228                 putCharUnsafe(val, index, c);
1229             } catch (IndexOutOfBoundsException e) {
1230                 throwAssertionError(e);
1231             }
1232         }
1233 
1234         /**
1235          * This is a variant of {@link Integer#getChars(int, int, byte[])}, but for
1236          * UTF-16 coder.
1237          *
1238          * @param i     value to convert
1239          * @param index next index, after the least significant digit
1240          * @param buf   target buffer, UTF16-coded.
1241          * @return index of the most significant digit or minus sign, if present
1242          */
1243         static int getChars(int i, int index, byte[] buf) {
1244             int q, r;
1245             int charPos = index;
1246 
1247             boolean negative = (i < 0);
1248             if (!negative) {
1249                 i = -i;
1250             }
1251 
1252             // Get 2 digits/iteration using ints
1253             while (i <= -100) {
1254                 q = i / 100;
1255                 r = (q * 100) - i;
1256                 i = q;
1257                 Trusted.putChar(buf, --charPos, Integer.DigitOnes[r]);
1258                 Trusted.putChar(buf, --charPos, Integer.DigitTens[r]);
1259             }
1260 
1261             // We know there are at most two digits left at this point.
1262             q = i / 10;
1263             r = (q * 10) - i;
1264             Trusted.putChar(buf, --charPos, '0' + r);
1265 
1266             // Whatever left is the remaining digit.
1267             if (q < 0) {
1268                 Trusted.putChar(buf, --charPos, '0' - q);
1269             }
1270 
1271             if (negative) {
1272                 Trusted.putChar(buf, --charPos, '-');
1273             }
1274             return charPos;
1275         }
1276 
1277         /**
1278          * This is a variant of {@link Long#getChars(long, int, byte[])}, but for
1279          * UTF-16 coder.
1280          *
1281          * @param i     value to convert
1282          * @param index next index, after the least significant digit
1283          * @param buf   target buffer, UTF16-coded.
1284          * @return index of the most significant digit or minus sign, if present
1285          */
1286         static int getChars(long i, int index, byte[] buf) {
1287             long q;
1288             int r;
1289             int charPos = index;
1290 
1291             boolean negative = (i < 0);
1292             if (!negative) {
1293                 i = -i;
1294             }
1295 
1296             // Get 2 digits/iteration using longs until quotient fits into an int
1297             while (i <= Integer.MIN_VALUE) {
1298                 q = i / 100;
1299                 r = (int)((q * 100) - i);
1300                 i = q;
1301                 Trusted.putChar(buf, --charPos, Integer.DigitOnes[r]);
1302                 Trusted.putChar(buf, --charPos, Integer.DigitTens[r]);
1303             }
1304 
1305             // Get 2 digits/iteration using ints
1306             int q2;
1307             int i2 = (int)i;
1308             while (i2 <= -100) {
1309                 q2 = i2 / 100;
1310                 r  = (q2 * 100) - i2;
1311                 i2 = q2;
1312                 Trusted.putChar(buf, --charPos, Integer.DigitOnes[r]);
1313                 Trusted.putChar(buf, --charPos, Integer.DigitTens[r]);
1314             }
1315 
1316             // We know there are at most two digits left at this point.
1317             q2 = i2 / 10;
1318             r  = (q2 * 10) - i2;
1319             Trusted.putChar(buf, --charPos, '0' + r);
1320 
1321             // Whatever left is the remaining digit.
1322             if (q2 < 0) {
1323                 Trusted.putChar(buf, --charPos, '0' - q2);
1324             }
1325 
1326             if (negative) {
1327                 Trusted.putChar(buf, --charPos, '-');
1328             }
1329             return charPos;
1330         }
1331 
1332     }
1333 
1334     public static void checkIndex(int off, byte[] val) {
1335         String.checkIndex(off, length(val));
1336     }
1337 
1338     public static void checkOffset(int off, byte[] val) {
1339         String.checkOffset(off, length(val));
1340     }
1341 
1342     public static void checkBoundsBeginEnd(int begin, int end, byte[] val) {
1343         String.checkBoundsBeginEnd(begin, end, length(val));
1344     }
1345 
1346     public static void checkBoundsOffCount(int offset, int count, byte[] val) {
1347         String.checkBoundsOffCount(offset, count, length(val));
1348     }
1349 
1350 }