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 }