1 /* 2 * Copyright (c) 2015, 2016, 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 34 import static java.lang.String.UTF16; 35 import static java.lang.String.LATIN1; 36 import static java.lang.String.checkIndex; 37 import static java.lang.String.checkOffset; 38 import static java.lang.String.checkBoundsOffCount; 39 import static java.lang.String.checkBoundsBeginEnd; 40 41 final class StringUTF16 { 42 43 public static byte[] newBytesFor(int len) { 44 if (len < 0) { 45 throw new NegativeArraySizeException(); 46 } 47 if (len > MAX_LENGTH) { 48 throw new OutOfMemoryError("UTF16 String size is " + len + 49 ", should be less than " + MAX_LENGTH); 50 } 51 return new byte[len << 1]; 52 } 53 54 @HotSpotIntrinsicCandidate 55 public static void putChar(byte[] val, int index, int c) { 56 index <<= 1; 57 val[index++] = (byte)(c >> HI_BYTE_SHIFT); 58 val[index] = (byte)(c >> LO_BYTE_SHIFT); 59 } 60 61 @HotSpotIntrinsicCandidate 62 public static char getChar(byte[] val, int index) { 63 index <<= 1; 64 return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) | 65 ((val[index] & 0xff) << LO_BYTE_SHIFT)); 66 } 67 68 public static char charAt(byte[] value, int index) { 69 if (index < 0 || index >= value.length >> 1) { 70 throw new StringIndexOutOfBoundsException(index); 71 } 72 return getChar(value, index); 73 } 74 75 public static int length(byte[] value) { 76 return value.length >> 1; 77 } 78 79 public static int codePointAt(byte[] value, int index, int end) { 80 char c1 = getChar(value, index); 81 if (Character.isHighSurrogate(c1) && ++index < end) { 82 char c2 = getChar(value, index); 83 if (Character.isLowSurrogate(c2)) { 84 return Character.toCodePoint(c1, c2); 85 } 86 } 87 return c1; 88 } 89 90 public static int codePointBefore(byte[] value, int index) { 91 char c2 = getChar(value, --index); 92 if (Character.isLowSurrogate(c2) && index > 0) { 93 char c1 = getChar(value, --index); 94 if (Character.isHighSurrogate(c1)) { 95 return Character.toCodePoint(c1, c2); 96 } 97 } 98 return c2; 99 } 100 101 public static int codePointCount(byte[] value, int beginIndex, int endIndex) { 102 int count = endIndex - beginIndex; 103 for (int i = beginIndex; i < endIndex; ) { 104 if (Character.isHighSurrogate(getChar(value, i++)) && 105 i < endIndex && 106 Character.isLowSurrogate(getChar(value, i))) { 107 count--; 108 i++; 109 } 110 } 111 return count; 112 } 113 114 public static char[] toChars(byte[] value) { 115 char[] dst = new char[value.length >> 1]; 116 getChars(value, 0, dst.length, dst, 0); 117 return dst; 118 } 119 120 @HotSpotIntrinsicCandidate 121 public static byte[] toBytes(char[] value, int off, int len) { 122 byte[] val = newBytesFor(len); 123 for (int i = 0; i < len; i++) { 124 putChar(val, i, value[off]); 125 off++; 126 } 127 return val; 128 } 129 130 public static byte[] compress(char[] val, int off, int len) { 131 byte[] ret = new byte[len]; 132 if (compress(val, off, ret, 0, len) == len) { 133 return ret; 134 } 135 return null; 136 } 137 138 public static byte[] compress(byte[] val, int off, int len) { 139 byte[] ret = new byte[len]; 140 if (compress(val, off, ret, 0, len) == len) { 141 return ret; 142 } 143 return null; 144 } 145 146 // compressedCopy char[] -> byte[] 147 @HotSpotIntrinsicCandidate 148 public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) { 149 for (int i = 0; i < len; i++) { 150 char c = src[srcOff]; 151 if (c > 0xFF) { 152 len = 0; 153 break; 154 } 155 dst[dstOff] = (byte)c; 156 srcOff++; 157 dstOff++; 158 } 159 return len; 160 } 161 162 // compressedCopy byte[] -> byte[] 163 @HotSpotIntrinsicCandidate 164 public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { 165 // We need a range check here because 'getChar' has no checks 166 checkBoundsOffCount(srcOff << 1, len << 1, src.length); 167 for (int i = 0; i < len; i++) { 168 char c = getChar(src, srcOff); 169 if (c > 0xFF) { 170 len = 0; 171 break; 172 } 173 dst[dstOff] = (byte)c; 174 srcOff++; 175 dstOff++; 176 } 177 return len; 178 } 179 180 public static byte[] toBytes(int[] val, int index, int len) { 181 final int end = index + len; 182 // Pass 1: Compute precise size of char[] 183 int n = len; 184 for (int i = index; i < end; i++) { 185 int cp = val[i]; 186 if (Character.isBmpCodePoint(cp)) 187 continue; 188 else if (Character.isValidCodePoint(cp)) 189 n++; 190 else throw new IllegalArgumentException(Integer.toString(cp)); 191 } 192 // Pass 2: Allocate and fill in <high, low> pair 193 byte[] buf = newBytesFor(n); 194 for (int i = index, j = 0; i < end; i++, j++) { 195 int cp = val[i]; 196 if (Character.isBmpCodePoint(cp)) { 197 putChar(buf, j, cp); 198 } else { 199 putChar(buf, j++, Character.highSurrogate(cp)); 200 putChar(buf, j, Character.lowSurrogate(cp)); 201 } 202 } 203 return buf; 204 } 205 206 public static byte[] toBytes(char c) { 207 byte[] result = new byte[2]; 208 putChar(result, 0, c); 209 return result; 210 } 211 212 @HotSpotIntrinsicCandidate 213 public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) { 214 // We need a range check here because 'getChar' has no checks 215 if (srcBegin < srcEnd) { 216 checkBoundsOffCount(srcBegin << 1, (srcEnd - srcBegin) << 1, value.length); 217 } 218 for (int i = srcBegin; i < srcEnd; i++) { 219 dst[dstBegin++] = getChar(value, i); 220 } 221 } 222 223 /* @see java.lang.String.getBytes(int, int, byte[], int) */ 224 public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) { 225 srcBegin <<= 1; 226 srcEnd <<= 1; 227 for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) { 228 dst[dstBegin++] = value[i]; 229 } 230 } 231 232 @HotSpotIntrinsicCandidate 233 public static boolean equals(byte[] value, byte[] other) { 234 if (value.length == other.length) { 235 int len = value.length >> 1; 236 for (int i = 0; i < len; i++) { 237 if (getChar(value, i) != getChar(other, i)) { 238 return false; 239 } 240 } 241 return true; 242 } 243 return false; 244 } 245 246 @HotSpotIntrinsicCandidate 247 public static int compareTo(byte[] value, byte[] other) { 248 int len1 = length(value); 249 int len2 = length(other); 250 int lim = Math.min(len1, len2); 251 for (int k = 0; k < lim; k++) { 252 char c1 = getChar(value, k); 253 char c2 = getChar(other, k); 254 if (c1 != c2) { 255 return c1 - c2; 256 } 257 } 258 return len1 - len2; 259 } 260 261 @HotSpotIntrinsicCandidate 262 public static int compareToLatin1(byte[] value, byte[] other) { 263 return -StringLatin1.compareToUTF16(other, value); 264 } 265 266 public static int compareToCI(byte[] value, byte[] other) { 267 int len1 = length(value); 268 int len2 = length(other); 269 int lim = Math.min(len1, len2); 270 for (int k = 0; k < lim; k++) { 271 char c1 = getChar(value, k); 272 char c2 = getChar(other, k); 273 if (c1 != c2) { 274 c1 = Character.toUpperCase(c1); 275 c2 = Character.toUpperCase(c2); 276 if (c1 != c2) { 277 c1 = Character.toLowerCase(c1); 278 c2 = Character.toLowerCase(c2); 279 if (c1 != c2) { 280 return c1 - c2; 281 } 282 } 283 } 284 } 285 return len1 - len2; 286 } 287 288 public static int compareToCI_Latin1(byte[] value, byte[] other) { 289 return -StringLatin1.compareToCI_UTF16(other, value); 290 } 291 292 public static int hashCode(byte[] value) { 293 int h = 0; 294 int length = value.length >> 1; 295 for (int i = 0; i < length; i++) { 296 h = 31 * h + getChar(value, i); 297 } 298 return h; 299 } 300 301 public static int indexOf(byte[] value, int ch, int fromIndex) { 302 int max = value.length >> 1; 303 if (fromIndex < 0) { 304 fromIndex = 0; 305 } else if (fromIndex >= max) { 306 // Note: fromIndex might be near -1>>>1. 307 return -1; 308 } 309 if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { 310 // handle most cases here (ch is a BMP code point or a 311 // negative value (invalid code point)) 312 return indexOfChar(value, ch, fromIndex, max); 313 } else { 314 return indexOfSupplementary(value, ch, fromIndex, max); 315 } 316 } 317 318 @HotSpotIntrinsicCandidate 319 public static int indexOf(byte[] value, byte[] str) { 320 if (str.length == 0) { 321 return 0; 322 } 323 if (value.length == 0) { 324 return -1; 325 } 326 return indexOf(value, length(value), str, length(str), 0); 327 } 328 329 @HotSpotIntrinsicCandidate 330 public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { 331 char first = getChar(str, 0); 332 int max = (valueCount - strCount); 333 for (int i = fromIndex; i <= max; i++) { 334 // Look for first character. 335 if (getChar(value, i) != first) { 336 while (++i <= max && getChar(value, i) != first); 337 } 338 // Found first character, now look at the rest of value 339 if (i <= max) { 340 int j = i + 1; 341 int end = j + strCount - 1; 342 for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++); 343 if (j == end) { 344 // Found whole string. 345 return i; 346 } 347 } 348 } 349 return -1; 350 } 351 352 /** 353 * Handles indexOf Latin1 substring in UTF16 string. 354 */ 355 @HotSpotIntrinsicCandidate 356 public static int indexOfLatin1(byte[] value, byte[] str) { 357 if (str.length == 0) { 358 return 0; 359 } 360 if (value.length == 0) { 361 return -1; 362 } 363 return indexOfLatin1(value, length(value), str, str.length, 0); 364 } 365 366 @HotSpotIntrinsicCandidate 367 public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { 368 char first = (char)(tgt[0] & 0xff); 369 int max = (srcCount - tgtCount); 370 for (int i = fromIndex; i <= max; i++) { 371 // Look for first character. 372 if (getChar(src, i) != first) { 373 while (++i <= max && getChar(src, i) != first); 374 } 375 // Found first character, now look at the rest of v2 376 if (i <= max) { 377 int j = i + 1; 378 int end = j + tgtCount - 1; 379 for (int k = 1; 380 j < end && getChar(src, j) == (tgt[k] & 0xff); 381 j++, k++); 382 if (j == end) { 383 // Found whole string. 384 return i; 385 } 386 } 387 } 388 return -1; 389 } 390 391 @HotSpotIntrinsicCandidate 392 private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) { 393 for (int i = fromIndex; i < max; i++) { 394 if (getChar(value, i) == ch) { 395 return i; 396 } 397 } 398 return -1; 399 } 400 401 /** 402 * Handles (rare) calls of indexOf with a supplementary character. 403 */ 404 private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) { 405 if (Character.isValidCodePoint(ch)) { 406 final char hi = Character.highSurrogate(ch); 407 final char lo = Character.lowSurrogate(ch); 408 for (int i = fromIndex; i < max - 1; i++) { 409 if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) { 410 return i; 411 } 412 } 413 } 414 return -1; 415 } 416 417 // srcCoder == UTF16 && tgtCoder == UTF16 418 public static int lastIndexOf(byte[] src, int srcCount, 419 byte[] tgt, int tgtCount, int fromIndex) { 420 int min = tgtCount - 1; 421 int i = min + fromIndex; 422 int strLastIndex = tgtCount - 1; 423 char strLastChar = getChar(tgt, strLastIndex); 424 425 startSearchForLastChar: 426 while (true) { 427 while (i >= min && getChar(src, i) != strLastChar) { 428 i--; 429 } 430 if (i < min) { 431 return -1; 432 } 433 int j = i - 1; 434 int start = j - strLastIndex; 435 int k = strLastIndex - 1; 436 while (j > start) { 437 if (getChar(src, j--) != getChar(tgt, k--)) { 438 i--; 439 continue startSearchForLastChar; 440 } 441 } 442 return start + 1; 443 } 444 } 445 446 public static int lastIndexOf(byte[] value, int ch, int fromIndex) { 447 if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { 448 // handle most cases here (ch is a BMP code point or a 449 // negative value (invalid code point)) 450 int i = Math.min(fromIndex, (value.length >> 1) - 1); 451 for (; i >= 0; i--) { 452 if (getChar(value, i) == ch) { 453 return i; 454 } 455 } 456 return -1; 457 } else { 458 return lastIndexOfSupplementary(value, ch, fromIndex); 459 } 460 } 461 462 /** 463 * Handles (rare) calls of lastIndexOf with a supplementary character. 464 */ 465 private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) { 466 if (Character.isValidCodePoint(ch)) { 467 char hi = Character.highSurrogate(ch); 468 char lo = Character.lowSurrogate(ch); 469 int i = Math.min(fromIndex, (value.length >> 1) - 2); 470 for (; i >= 0; i--) { 471 if (getChar(value, i) == hi && getChar(value, i + 1) == lo) { 472 return i; 473 } 474 } 475 } 476 return -1; 477 } 478 479 public static String replace(byte[] value, char oldChar, char newChar) { 480 int len = value.length >> 1; 481 int i = -1; 482 while (++i < len) { 483 if (getChar(value, i) == oldChar) { 484 break; 485 } 486 } 487 if (i < len) { 488 byte buf[] = new byte[value.length]; 489 for (int j = 0; j < i; j++) { 490 putChar(buf, j, getChar(value, j)); // TBD:arraycopy? 491 } 492 while (i < len) { 493 char c = getChar(value, i); 494 putChar(buf, i, c == oldChar ? newChar : c); 495 i++; 496 } 497 // Check if we should try to compress to latin1 498 if (String.COMPACT_STRINGS && 499 !StringLatin1.canEncode(oldChar) && 500 StringLatin1.canEncode(newChar)) { 501 byte[] val = compress(buf, 0, len); 502 if (val != null) { 503 return new String(val, LATIN1); 504 } 505 } 506 return new String(buf, UTF16); 507 } 508 return null; 509 } 510 511 public static boolean regionMatchesCI(byte[] value, int toffset, 512 byte[] other, int ooffset, int len) { 513 int last = toffset + len; 514 while (toffset < last) { 515 char c1 = getChar(value, toffset++); 516 char c2 = getChar(other, ooffset++); 517 if (c1 == c2) { 518 continue; 519 } 520 // try converting both characters to uppercase. 521 // If the results match, then the comparison scan should 522 // continue. 523 char u1 = Character.toUpperCase(c1); 524 char u2 = Character.toUpperCase(c2); 525 if (u1 == u2) { 526 continue; 527 } 528 // Unfortunately, conversion to uppercase does not work properly 529 // for the Georgian alphabet, which has strange rules about case 530 // conversion. So we need to make one last check before 531 // exiting. 532 if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 533 continue; 534 } 535 return false; 536 } 537 return true; 538 } 539 540 public static boolean regionMatchesCI_Latin1(byte[] value, int toffset, 541 byte[] other, int ooffset, 542 int len) { 543 return StringLatin1.regionMatchesCI_UTF16(other, ooffset, value, toffset, len); 544 } 545 546 public static String toLowerCase(String str, byte[] value, Locale locale) { 547 if (locale == null) { 548 throw new NullPointerException(); 549 } 550 int first; 551 boolean hasSurr = false; 552 final int len = value.length >> 1; 553 554 // Now check if there are any characters that need to be changed, or are surrogate 555 for (first = 0 ; first < len; first++) { 556 int cp = (int)getChar(value, first); 557 if (Character.isSurrogate((char)cp)) { 558 hasSurr = true; 559 break; 560 } 561 if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR 562 break; 563 } 564 } 565 if (first == len) 566 return str; 567 byte[] result = new byte[value.length]; 568 System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few 569 // lowerCase characters. 570 String lang = locale.getLanguage(); 571 if (lang == "tr" || lang == "az" || lang == "lt") { 572 return toLowerCaseEx(str, value, result, first, locale, true); 573 } 574 if (hasSurr) { 575 return toLowerCaseEx(str, value, result, first, locale, false); 576 } 577 int bits = 0; 578 for (int i = first; i < len; i++) { 579 int cp = (int)getChar(value, i); 580 if (cp == '\u03A3' || // GREEK CAPITAL LETTER SIGMA 581 Character.isSurrogate((char)cp)) { 582 return toLowerCaseEx(str, value, result, i, locale, false); 583 } 584 if (cp == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE 585 return toLowerCaseEx(str, value, result, i, locale, true); 586 } 587 cp = Character.toLowerCase(cp); 588 if (!Character.isBmpCodePoint(cp)) { 589 return toLowerCaseEx(str, value, result, i, locale, false); 590 } 591 bits |= cp; 592 putChar(result, i, cp); 593 } 594 if (bits > 0xFF) { 595 return new String(result, UTF16); 596 } else { 597 return newString(result, 0, len); 598 } 599 } 600 601 private static String toLowerCaseEx(String str, byte[] value, 602 byte[] result, int first, Locale locale, 603 boolean localeDependent) { 604 int resultOffset = first; 605 int length = value.length >> 1; 606 int srcCount; 607 for (int i = first; i < length; i += srcCount) { 608 int srcChar = getChar(value, i); 609 int lowerChar; 610 char[] lowerCharArray; 611 srcCount = 1; 612 if (Character.isSurrogate((char)srcChar)) { 613 srcChar = codePointAt(value, i, length); 614 srcCount = Character.charCount(srcChar); 615 } 616 if (localeDependent || 617 srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA 618 srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE 619 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale); 620 } else { 621 lowerChar = Character.toLowerCase(srcChar); 622 } 623 if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp 624 putChar(result, resultOffset++, lowerChar); 625 } else { 626 if (lowerChar == Character.ERROR) { 627 lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale); 628 } else { 629 lowerCharArray = Character.toChars(lowerChar); 630 } 631 /* Grow result if needed */ 632 int mapLen = lowerCharArray.length; 633 if (mapLen > srcCount) { 634 byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount); 635 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 636 result = result2; 637 } 638 for (int x = 0; x < mapLen; ++x) { 639 putChar(result, resultOffset++, lowerCharArray[x]); 640 } 641 } 642 } 643 return newString(result, 0, resultOffset); 644 } 645 646 public static String toUpperCase(String str, byte[] value, Locale locale) { 647 if (locale == null) { 648 throw new NullPointerException(); 649 } 650 int first; 651 boolean hasSurr = false; 652 final int len = value.length >> 1; 653 654 // Now check if there are any characters that need to be changed, or are surrogate 655 for (first = 0 ; first < len; first++) { 656 int cp = (int)getChar(value, first); 657 if (Character.isSurrogate((char)cp)) { 658 hasSurr = true; 659 break; 660 } 661 if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR 662 break; 663 } 664 } 665 if (first == len) { 666 return str; 667 } 668 byte[] result = new byte[value.length]; 669 System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few 670 // upperCase characters. 671 String lang = locale.getLanguage(); 672 if (lang == "tr" || lang == "az" || lang == "lt") { 673 return toUpperCaseEx(str, value, result, first, locale, true); 674 } 675 if (hasSurr) { 676 return toUpperCaseEx(str, value, result, first, locale, false); 677 } 678 int bits = 0; 679 for (int i = first; i < len; i++) { 680 int cp = (int)getChar(value, i); 681 if (Character.isSurrogate((char)cp)) { 682 return toUpperCaseEx(str, value, result, i, locale, false); 683 } 684 cp = Character.toUpperCaseEx(cp); 685 if (!Character.isBmpCodePoint(cp)) { // Character.ERROR is not bmp 686 return toUpperCaseEx(str, value, result, i, locale, false); 687 } 688 bits |= cp; 689 putChar(result, i, cp); 690 } 691 if (bits > 0xFF) { 692 return new String(result, UTF16); 693 } else { 694 return newString(result, 0, len); 695 } 696 } 697 698 private static String toUpperCaseEx(String str, byte[] value, 699 byte[] result, int first, 700 Locale locale, boolean localeDependent) 701 { 702 int resultOffset = first; 703 int length = value.length >> 1; 704 int srcCount; 705 for (int i = first; i < length; i += srcCount) { 706 int srcChar = getChar(value, i); 707 int upperChar; 708 char[] upperCharArray; 709 srcCount = 1; 710 if (Character.isSurrogate((char)srcChar)) { 711 srcChar = codePointAt(value, i, length); 712 srcCount = Character.charCount(srcChar); 713 } 714 if (localeDependent) { 715 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale); 716 } else { 717 upperChar = Character.toUpperCaseEx(srcChar); 718 } 719 if (Character.isBmpCodePoint(upperChar)) { 720 putChar(result, resultOffset++, upperChar); 721 } else { 722 if (upperChar == Character.ERROR) { 723 if (localeDependent) { 724 upperCharArray = 725 ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale); 726 } else { 727 upperCharArray = Character.toUpperCaseCharArray(srcChar); 728 } 729 } else { 730 upperCharArray = Character.toChars(upperChar); 731 } 732 /* Grow result if needed */ 733 int mapLen = upperCharArray.length; 734 if (mapLen > srcCount) { 735 byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount); 736 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 737 result = result2; 738 } 739 for (int x = 0; x < mapLen; ++x) { 740 putChar(result, resultOffset++, upperCharArray[x]); 741 } 742 } 743 } 744 return newString(result, 0, resultOffset); 745 } 746 747 public static String trim(byte[] value) { 748 int length = value.length >> 1; 749 int len = length; 750 int st = 0; 751 while (st < len && getChar(value, st) <= ' ') { 752 st++; 753 } 754 while (st < len && getChar(value, len - 1) <= ' ') { 755 len--; 756 } 757 return ((st > 0) || (len < length )) ? 758 new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) : 759 null; 760 } 761 762 public static void putChars(byte[] val, int index, char[] str, int off, int end) { 763 while (off < end) { 764 putChar(val, index++, str[off++]); 765 } 766 } 767 768 public static String newString(byte[] val, int index, int len) { 769 if (String.COMPACT_STRINGS) { 770 byte[] buf = compress(val, index, len); 771 if (buf != null) { 772 return new String(buf, LATIN1); 773 } 774 } 775 int last = index + len; 776 return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16); 777 } 778 779 public static void fillNull(byte[] val, int index, int end) { 780 Arrays.fill(val, index << 1, end << 1, (byte)0); 781 } 782 783 static class CharsSpliterator implements Spliterator.OfInt { 784 private final byte[] array; 785 private int index; // current index, modified on advance/split 786 private final int fence; // one past last index 787 private final int cs; 788 789 CharsSpliterator(byte[] array, int acs) { 790 this(array, 0, array.length >> 1, acs); 791 } 792 793 CharsSpliterator(byte[] array, int origin, int fence, int acs) { 794 this.array = array; 795 this.index = origin; 796 this.fence = fence; 797 this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED 798 | Spliterator.SUBSIZED; 799 } 800 801 @Override 802 public OfInt trySplit() { 803 int lo = index, mid = (lo + fence) >>> 1; 804 return (lo >= mid) 805 ? null 806 : new CharsSpliterator(array, lo, index = mid, cs); 807 } 808 809 @Override 810 public void forEachRemaining(IntConsumer action) { 811 byte[] a; int i, hi; // hoist accesses and checks from loop 812 if (action == null) 813 throw new NullPointerException(); 814 if (((a = array).length >> 1) >= (hi = fence) && 815 (i = index) >= 0 && i < (index = hi)) { 816 do { 817 action.accept(charAt(a, i)); 818 } while (++i < hi); 819 } 820 } 821 822 @Override 823 public boolean tryAdvance(IntConsumer action) { 824 if (action == null) 825 throw new NullPointerException(); 826 int i = index; 827 if (i >= 0 && i < fence) { 828 action.accept(charAt(array, i)); 829 index++; 830 return true; 831 } 832 return false; 833 } 834 835 @Override 836 public long estimateSize() { return (long)(fence - index); } 837 838 @Override 839 public int characteristics() { 840 return cs; 841 } 842 } 843 844 static class CodePointsSpliterator implements Spliterator.OfInt { 845 private final byte[] array; 846 private int index; // current index, modified on advance/split 847 private final int fence; // one past last index 848 private final int cs; 849 850 CodePointsSpliterator(byte[] array, int acs) { 851 this(array, 0, array.length >> 1, acs); 852 } 853 854 CodePointsSpliterator(byte[] array, int origin, int fence, int acs) { 855 this.array = array; 856 this.index = origin; 857 this.fence = fence; 858 this.cs = acs | Spliterator.ORDERED; 859 } 860 861 @Override 862 public OfInt trySplit() { 863 int lo = index, mid = (lo + fence) >>> 1; 864 if (lo >= mid) 865 return null; 866 867 int midOneLess; 868 // If the mid-point intersects a surrogate pair 869 if (Character.isLowSurrogate(charAt(array, mid)) && 870 Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) { 871 // If there is only one pair it cannot be split 872 if (lo >= midOneLess) 873 return null; 874 // Shift the mid-point to align with the surrogate pair 875 return new CodePointsSpliterator(array, lo, index = midOneLess, cs); 876 } 877 return new CodePointsSpliterator(array, lo, index = mid, cs); 878 } 879 880 @Override 881 public void forEachRemaining(IntConsumer action) { 882 byte[] a; int i, hi; // hoist accesses and checks from loop 883 if (action == null) 884 throw new NullPointerException(); 885 if (((a = array).length >> 1) >= (hi = fence) && 886 (i = index) >= 0 && i < (index = hi)) { 887 do { 888 i = advance(a, i, hi, action); 889 } while (i < hi); 890 } 891 } 892 893 @Override 894 public boolean tryAdvance(IntConsumer action) { 895 if (action == null) 896 throw new NullPointerException(); 897 if (index >= 0 && index < fence) { 898 index = advance(array, index, fence, action); 899 return true; 900 } 901 return false; 902 } 903 904 // Advance one code point from the index, i, and return the next 905 // index to advance from 906 private static int advance(byte[] a, int i, int hi, IntConsumer action) { 907 char c1 = charAt(a, i++); 908 int cp = c1; 909 if (Character.isHighSurrogate(c1) && i < hi) { 910 char c2 = charAt(a, i); 911 if (Character.isLowSurrogate(c2)) { 912 i++; 913 cp = Character.toCodePoint(c1, c2); 914 } 915 } 916 action.accept(cp); 917 return i; 918 } 919 920 @Override 921 public long estimateSize() { return (long)(fence - index); } 922 923 @Override 924 public int characteristics() { 925 return cs; 926 } 927 } 928 929 //////////////////////////////////////////////////////////////// 930 931 public static void putCharSB(byte[] val, int index, int c) { 932 checkIndex(index, val.length >> 1); 933 putChar(val, index, c); 934 } 935 936 public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) { 937 checkBoundsOffCount(index, index + end - off, val.length >> 1); 938 putChars(val, index, ca, off, end); 939 } 940 941 public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) { 942 checkBoundsOffCount(index, end - off, val.length >> 1); 943 for (int i = off; i < end; i++) { 944 putChar(val, index++, s.charAt(i)); 945 } 946 } 947 948 public static int codePointAtSB(byte[] val, int index, int end) { 949 checkOffset(end, val.length >> 1); 950 return codePointAt(val, index, end); 951 } 952 953 public static int codePointBeforeSB(byte[] val, int index) { 954 checkOffset(index, val.length >> 1); 955 return codePointBefore(val, index); 956 } 957 958 public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) { 959 checkBoundsBeginEnd(beginIndex, endIndex, val.length >> 1); 960 return codePointCount(val, beginIndex, endIndex); 961 } 962 963 //////////////////////////////////////////////////////////////// 964 965 private static native boolean isBigEndian(); 966 967 static final int HI_BYTE_SHIFT; 968 static final int LO_BYTE_SHIFT; 969 static { 970 if (isBigEndian()) { 971 HI_BYTE_SHIFT = 8; 972 LO_BYTE_SHIFT = 0; 973 } else { 974 HI_BYTE_SHIFT = 0; 975 LO_BYTE_SHIFT = 8; 976 } 977 } 978 979 static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; 980 }