1 /* 2 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.util.Arrays; 29 import java.util.Locale; 30 import java.util.Spliterator; 31 import java.util.function.Consumer; 32 import java.util.function.IntConsumer; 33 import java.util.stream.Stream; 34 import java.util.stream.StreamSupport; 35 import jdk.internal.HotSpotIntrinsicCandidate; 36 import jdk.internal.vm.annotation.ForceInline; 37 import jdk.internal.vm.annotation.DontInline; 38 39 import static java.lang.String.UTF16; 40 import static java.lang.String.LATIN1; 41 42 final class StringUTF16 { 43 44 public static byte[] newBytesFor(int len) { 45 if (len < 0) { 46 throw new NegativeArraySizeException(); 47 } 48 if (len > MAX_LENGTH) { 49 throw new OutOfMemoryError("UTF16 String size is " + len + 50 ", should be less than " + MAX_LENGTH); 51 } 52 return new byte[len << 1]; 53 } 54 55 @HotSpotIntrinsicCandidate 56 // intrinsic performs no bounds checks 57 static void putChar(byte[] val, int index, int c) { 58 assert index >= 0 && index < length(val) : "Trusted caller missed bounds check"; 59 index <<= 1; 60 val[index++] = (byte)(c >> HI_BYTE_SHIFT); 61 val[index] = (byte)(c >> LO_BYTE_SHIFT); 62 } 63 64 @HotSpotIntrinsicCandidate 65 // intrinsic performs no bounds checks 66 static char getChar(byte[] val, int index) { 67 assert index >= 0 && index < length(val) : "Trusted caller missed bounds check"; 68 index <<= 1; 69 return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) | 70 ((val[index] & 0xff) << LO_BYTE_SHIFT)); 71 } 72 73 public static int length(byte[] value) { 74 return value.length >> 1; 75 } 76 77 private static int codePointAt(byte[] value, int index, int end, boolean checked) { 78 assert index < end; 79 if (checked) { 80 checkIndex(index, value); 81 } 82 char c1 = getChar(value, index); 83 if (Character.isHighSurrogate(c1) && ++index < end) { 84 if (checked) { 85 checkIndex(index, value); 86 } 87 char c2 = getChar(value, index); 88 if (Character.isLowSurrogate(c2)) { 89 return Character.toCodePoint(c1, c2); 90 } 91 } 92 return c1; 93 } 94 95 public static int codePointAt(byte[] value, int index, int end) { 96 return codePointAt(value, index, end, false /* unchecked */); 97 } 98 99 private static int codePointBefore(byte[] value, int index, boolean checked) { 100 --index; 101 if (checked) { 102 checkIndex(index, value); 103 } 104 char c2 = getChar(value, index); 105 if (Character.isLowSurrogate(c2) && index > 0) { 106 --index; 107 if (checked) { 108 checkIndex(index, value); 109 } 110 char c1 = getChar(value, index); 111 if (Character.isHighSurrogate(c1)) { 112 return Character.toCodePoint(c1, c2); 113 } 114 } 115 return c2; 116 } 117 118 public static int codePointBefore(byte[] value, int index) { 119 return codePointBefore(value, index, false /* unchecked */); 120 } 121 122 private static int codePointCount(byte[] value, int beginIndex, int endIndex, boolean checked) { 123 assert beginIndex <= endIndex; 124 int count = endIndex - beginIndex; 125 int i = beginIndex; 126 if (checked && i < endIndex) { 127 checkBoundsBeginEnd(i, endIndex, value); 128 } 129 for (; i < endIndex - 1; ) { 130 if (Character.isHighSurrogate(getChar(value, i++)) && 131 Character.isLowSurrogate(getChar(value, i))) { 132 count--; 133 i++; 134 } 135 } 136 return count; 137 } 138 139 public static int codePointCount(byte[] value, int beginIndex, int endIndex) { 140 return codePointCount(value, beginIndex, endIndex, false /* unchecked */); 141 } 142 143 public static char[] toChars(byte[] value) { 144 char[] dst = new char[value.length >> 1]; 145 getChars(value, 0, dst.length, dst, 0); 146 return dst; 147 } 148 149 @HotSpotIntrinsicCandidate 150 public static byte[] toBytes(char[] value, int off, int len) { 151 byte[] val = newBytesFor(len); 152 for (int i = 0; i < len; i++) { 153 putChar(val, i, value[off]); 154 off++; 155 } 156 return val; 157 } 158 159 public static byte[] compress(char[] val, int off, int len) { 160 byte[] ret = new byte[len]; 161 if (compress(val, off, ret, 0, len) == len) { 162 return ret; 163 } 164 return null; 165 } 166 167 public static byte[] compress(byte[] val, int off, int len) { 168 byte[] ret = new byte[len]; 169 if (compress(val, off, ret, 0, len) == len) { 170 return ret; 171 } 172 return null; 173 } 174 175 // compressedCopy char[] -> byte[] 176 @HotSpotIntrinsicCandidate 177 public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) { 178 for (int i = 0; i < len; i++) { 179 char c = src[srcOff]; 180 if (c > 0xFF) { 181 len = 0; 182 break; 183 } 184 dst[dstOff] = (byte)c; 185 srcOff++; 186 dstOff++; 187 } 188 return len; 189 } 190 191 // compressedCopy byte[] -> byte[] 192 @HotSpotIntrinsicCandidate 193 public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { 194 // We need a range check here because 'getChar' has no checks 195 checkBoundsOffCount(srcOff, len, src); 196 for (int i = 0; i < len; i++) { 197 char c = getChar(src, srcOff); 198 if (c > 0xFF) { 199 len = 0; 200 break; 201 } 202 dst[dstOff] = (byte)c; 203 srcOff++; 204 dstOff++; 205 } 206 return len; 207 } 208 209 public static byte[] toBytes(int[] val, int index, int len) { 210 final int end = index + len; 211 // Pass 1: Compute precise size of char[] 212 int n = len; 213 for (int i = index; i < end; i++) { 214 int cp = val[i]; 215 if (Character.isBmpCodePoint(cp)) 216 continue; 217 else if (Character.isValidCodePoint(cp)) 218 n++; 219 else throw new IllegalArgumentException(Integer.toString(cp)); 220 } 221 // Pass 2: Allocate and fill in <high, low> pair 222 byte[] buf = newBytesFor(n); 223 for (int i = index, j = 0; i < end; i++, j++) { 224 int cp = val[i]; 225 if (Character.isBmpCodePoint(cp)) { 226 putChar(buf, j, cp); 227 } else { 228 putChar(buf, j++, Character.highSurrogate(cp)); 229 putChar(buf, j, Character.lowSurrogate(cp)); 230 } 231 } 232 return buf; 233 } 234 235 public static byte[] toBytes(char c) { 236 byte[] result = new byte[2]; 237 putChar(result, 0, c); 238 return result; 239 } 240 241 static byte[] toBytesSupplementary(int cp) { 242 byte[] result = new byte[4]; 243 putChar(result, 0, Character.highSurrogate(cp)); 244 putChar(result, 1, Character.lowSurrogate(cp)); 245 return result; 246 } 247 248 @HotSpotIntrinsicCandidate 249 public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) { 250 // We need a range check here because 'getChar' has no checks 251 if (srcBegin < srcEnd) { 252 checkBoundsOffCount(srcBegin, srcEnd - srcBegin, value); 253 } 254 for (int i = srcBegin; i < srcEnd; i++) { 255 dst[dstBegin++] = getChar(value, i); 256 } 257 } 258 259 /* @see java.lang.String.getBytes(int, int, byte[], int) */ 260 public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) { 261 srcBegin <<= 1; 262 srcEnd <<= 1; 263 for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) { 264 dst[dstBegin++] = value[i]; 265 } 266 } 267 268 @HotSpotIntrinsicCandidate 269 public static boolean equals(byte[] value, byte[] other) { 270 if (value.length == other.length) { 271 int len = value.length >> 1; 272 for (int i = 0; i < len; i++) { 273 if (getChar(value, i) != getChar(other, i)) { 274 return false; 275 } 276 } 277 return true; 278 } 279 return false; 280 } 281 282 @HotSpotIntrinsicCandidate 283 public static int compareTo(byte[] value, byte[] other) { 284 int len1 = length(value); 285 int len2 = length(other); 286 return compareValues(value, other, len1, len2); 287 } 288 289 /* 290 * Checks the boundary and then compares the byte arrays. 291 */ 292 public static int compareTo(byte[] value, byte[] other, int len1, int len2) { 293 checkOffset(len1, value); 294 checkOffset(len2, other); 295 296 return compareValues(value, other, len1, len2); 297 } 298 299 private static int compareValues(byte[] value, byte[] other, int len1, int len2) { 300 int lim = Math.min(len1, len2); 301 for (int k = 0; k < lim; k++) { 302 char c1 = getChar(value, k); 303 char c2 = getChar(other, k); 304 if (c1 != c2) { 305 return c1 - c2; 306 } 307 } 308 return len1 - len2; 309 } 310 311 @HotSpotIntrinsicCandidate 312 public static int compareToLatin1(byte[] value, byte[] other) { 313 return -StringLatin1.compareToUTF16(other, value); 314 } 315 316 public static int compareToLatin1(byte[] value, byte[] other, int len1, int len2) { 317 return -StringLatin1.compareToUTF16(other, value, len2, len1); 318 } 319 320 public static int compareToCI(byte[] value, byte[] other) { 321 int len1 = length(value); 322 int len2 = length(other); 323 int lim = Math.min(len1, len2); 324 for (int k = 0; k < lim; k++) { 325 char c1 = getChar(value, k); 326 char c2 = getChar(other, k); 327 if (c1 != c2) { 328 c1 = Character.toUpperCase(c1); 329 c2 = Character.toUpperCase(c2); 330 if (c1 != c2) { 331 c1 = Character.toLowerCase(c1); 332 c2 = Character.toLowerCase(c2); 333 if (c1 != c2) { 334 return c1 - c2; 335 } 336 } 337 } 338 } 339 return len1 - len2; 340 } 341 342 public static int compareToCI_Latin1(byte[] value, byte[] other) { 343 return -StringLatin1.compareToCI_UTF16(other, value); 344 } 345 346 public static int hashCode(byte[] value) { 347 int h = 0; 348 int length = value.length >> 1; 349 for (int i = 0; i < length; i++) { 350 h = 31 * h + getChar(value, i); 351 } 352 return h; 353 } 354 355 public static int indexOf(byte[] value, int ch, int fromIndex) { 356 int max = value.length >> 1; 357 if (fromIndex < 0) { 358 fromIndex = 0; 359 } else if (fromIndex >= max) { 360 // Note: fromIndex might be near -1>>>1. 361 return -1; 362 } 363 if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { 364 // handle most cases here (ch is a BMP code point or a 365 // negative value (invalid code point)) 366 return indexOfChar(value, ch, fromIndex, max); 367 } else { 368 return indexOfSupplementary(value, ch, fromIndex, max); 369 } 370 } 371 372 @HotSpotIntrinsicCandidate 373 public static int indexOf(byte[] value, byte[] str) { 374 if (str.length == 0) { 375 return 0; 376 } 377 if (value.length < str.length) { 378 return -1; 379 } 380 return indexOfUnsafe(value, length(value), str, length(str), 0); 381 } 382 383 @HotSpotIntrinsicCandidate 384 public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { 385 checkBoundsBeginEnd(fromIndex, valueCount, value); 386 checkBoundsBeginEnd(0, strCount, str); 387 return indexOfUnsafe(value, valueCount, str, strCount, fromIndex); 388 } 389 390 391 private static int indexOfUnsafe(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { 392 assert fromIndex >= 0; 393 assert strCount > 0; 394 assert strCount <= length(str); 395 assert valueCount >= strCount; 396 char first = getChar(str, 0); 397 int max = (valueCount - strCount); 398 for (int i = fromIndex; i <= max; i++) { 399 // Look for first character. 400 if (getChar(value, i) != first) { 401 while (++i <= max && getChar(value, i) != first); 402 } 403 // Found first character, now look at the rest of value 404 if (i <= max) { 405 int j = i + 1; 406 int end = j + strCount - 1; 407 for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++); 408 if (j == end) { 409 // Found whole string. 410 return i; 411 } 412 } 413 } 414 return -1; 415 } 416 417 418 /** 419 * Handles indexOf Latin1 substring in UTF16 string. 420 */ 421 @HotSpotIntrinsicCandidate 422 public static int indexOfLatin1(byte[] value, byte[] str) { 423 if (str.length == 0) { 424 return 0; 425 } 426 if (length(value) < str.length) { 427 return -1; 428 } 429 return indexOfLatin1Unsafe(value, length(value), str, str.length, 0); 430 } 431 432 @HotSpotIntrinsicCandidate 433 public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { 434 checkBoundsBeginEnd(fromIndex, srcCount, src); 435 String.checkBoundsBeginEnd(0, tgtCount, tgt.length); 436 return indexOfLatin1Unsafe(src, srcCount, tgt, tgtCount, fromIndex); 437 } 438 439 public static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { 440 assert fromIndex >= 0; 441 assert tgtCount > 0; 442 assert tgtCount <= tgt.length; 443 assert srcCount >= tgtCount; 444 char first = (char)(tgt[0] & 0xff); 445 int max = (srcCount - tgtCount); 446 for (int i = fromIndex; i <= max; i++) { 447 // Look for first character. 448 if (getChar(src, i) != first) { 449 while (++i <= max && getChar(src, i) != first); 450 } 451 // Found first character, now look at the rest of v2 452 if (i <= max) { 453 int j = i + 1; 454 int end = j + tgtCount - 1; 455 for (int k = 1; 456 j < end && getChar(src, j) == (tgt[k] & 0xff); 457 j++, k++); 458 if (j == end) { 459 // Found whole string. 460 return i; 461 } 462 } 463 } 464 return -1; 465 } 466 467 @HotSpotIntrinsicCandidate 468 private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) { 469 checkBoundsBeginEnd(fromIndex, max, value); 470 return indexOfCharUnsafe(value, ch, fromIndex, max); 471 } 472 473 private static int indexOfCharUnsafe(byte[] value, int ch, int fromIndex, int max) { 474 for (int i = fromIndex; i < max; i++) { 475 if (getChar(value, i) == ch) { 476 return i; 477 } 478 } 479 return -1; 480 } 481 482 /** 483 * Handles (rare) calls of indexOf with a supplementary character. 484 */ 485 private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) { 486 if (Character.isValidCodePoint(ch)) { 487 final char hi = Character.highSurrogate(ch); 488 final char lo = Character.lowSurrogate(ch); 489 checkBoundsBeginEnd(fromIndex, max, value); 490 for (int i = fromIndex; i < max - 1; i++) { 491 if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) { 492 return i; 493 } 494 } 495 } 496 return -1; 497 } 498 499 // srcCoder == UTF16 && tgtCoder == UTF16 500 public static int lastIndexOf(byte[] src, int srcCount, 501 byte[] tgt, int tgtCount, int fromIndex) { 502 assert fromIndex >= 0; 503 assert tgtCount > 0; 504 assert tgtCount <= length(tgt); 505 int min = tgtCount - 1; 506 int i = min + fromIndex; 507 int strLastIndex = tgtCount - 1; 508 509 checkIndex(strLastIndex, tgt); 510 char strLastChar = getChar(tgt, strLastIndex); 511 512 checkIndex(i, src); 513 514 startSearchForLastChar: 515 while (true) { 516 while (i >= min && getChar(src, i) != strLastChar) { 517 i--; 518 } 519 if (i < min) { 520 return -1; 521 } 522 int j = i - 1; 523 int start = j - strLastIndex; 524 int k = strLastIndex - 1; 525 while (j > start) { 526 if (getChar(src, j--) != getChar(tgt, k--)) { 527 i--; 528 continue startSearchForLastChar; 529 } 530 } 531 return start + 1; 532 } 533 } 534 535 public static int lastIndexOf(byte[] value, int ch, int fromIndex) { 536 if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { 537 // handle most cases here (ch is a BMP code point or a 538 // negative value (invalid code point)) 539 int i = Math.min(fromIndex, (value.length >> 1) - 1); 540 for (; i >= 0; i--) { 541 if (getChar(value, i) == ch) { 542 return i; 543 } 544 } 545 return -1; 546 } else { 547 return lastIndexOfSupplementary(value, ch, fromIndex); 548 } 549 } 550 551 /** 552 * Handles (rare) calls of lastIndexOf with a supplementary character. 553 */ 554 private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) { 555 if (Character.isValidCodePoint(ch)) { 556 char hi = Character.highSurrogate(ch); 557 char lo = Character.lowSurrogate(ch); 558 int i = Math.min(fromIndex, (value.length >> 1) - 2); 559 for (; i >= 0; i--) { 560 if (getChar(value, i) == hi && getChar(value, i + 1) == lo) { 561 return i; 562 } 563 } 564 } 565 return -1; 566 } 567 568 public static String replace(byte[] value, char oldChar, char newChar) { 569 int len = value.length >> 1; 570 int i = -1; 571 while (++i < len) { 572 if (getChar(value, i) == oldChar) { 573 break; 574 } 575 } 576 if (i < len) { 577 byte[] buf = new byte[value.length]; 578 for (int j = 0; j < i; j++) { 579 putChar(buf, j, getChar(value, j)); // TBD:arraycopy? 580 } 581 while (i < len) { 582 char c = getChar(value, i); 583 putChar(buf, i, c == oldChar ? newChar : c); 584 i++; 585 } 586 // Check if we should try to compress to latin1 587 if (String.COMPACT_STRINGS && 588 !StringLatin1.canEncode(oldChar) && 589 StringLatin1.canEncode(newChar)) { 590 byte[] val = compress(buf, 0, len); 591 if (val != null) { 592 return new String(val, LATIN1); 593 } 594 } 595 return new String(buf, UTF16); 596 } 597 return null; 598 } 599 600 public static String replace(byte[] value, int valLen, boolean valLat1, 601 byte[] targ, int targLen, boolean targLat1, 602 byte[] repl, int replLen, boolean replLat1) 603 { 604 assert targLen > 0; 605 assert !valLat1 || !targLat1 || !replLat1; 606 607 // Possible combinations of the arguments/result encodings: 608 // +---+--------+--------+--------+-----------------------+ 609 // | # | VALUE | TARGET | REPL | RESULT | 610 // +===+========+========+========+=======================+ 611 // | 1 | Latin1 | Latin1 | UTF16 | null or UTF16 | 612 // +---+--------+--------+--------+-----------------------+ 613 // | 2 | Latin1 | UTF16 | Latin1 | null | 614 // +---+--------+--------+--------+-----------------------+ 615 // | 3 | Latin1 | UTF16 | UTF16 | null | 616 // +---+--------+--------+--------+-----------------------+ 617 // | 4 | UTF16 | Latin1 | Latin1 | null or UTF16 | 618 // +---+--------+--------+--------+-----------------------+ 619 // | 5 | UTF16 | Latin1 | UTF16 | null or UTF16 | 620 // +---+--------+--------+--------+-----------------------+ 621 // | 6 | UTF16 | UTF16 | Latin1 | null, Latin1 or UTF16 | 622 // +---+--------+--------+--------+-----------------------+ 623 // | 7 | UTF16 | UTF16 | UTF16 | null or UTF16 | 624 // +---+--------+--------+--------+-----------------------+ 625 626 if (String.COMPACT_STRINGS && valLat1 && !targLat1) { 627 // combinations 2 or 3 628 return null; // for string to return this; 629 } 630 631 int i = (String.COMPACT_STRINGS && valLat1) 632 ? StringLatin1.indexOf(value, targ) : 633 (String.COMPACT_STRINGS && targLat1) 634 ? indexOfLatin1(value, targ) 635 : indexOf(value, targ); 636 if (i < 0) { 637 return null; // for string to return this; 638 } 639 640 // find and store indices of substrings to replace 641 int j, p = 0; 642 int[] pos = new int[16]; 643 pos[0] = i; 644 i += targLen; 645 while ((j = ((String.COMPACT_STRINGS && valLat1) 646 ? StringLatin1.indexOf(value, valLen, targ, targLen, i) : 647 (String.COMPACT_STRINGS && targLat1) 648 ? indexOfLatin1(value, valLen, targ, targLen, i) 649 : indexOf(value, valLen, targ, targLen, i))) > 0) 650 { 651 if (++p == pos.length) { 652 int cap = p + (p >> 1); 653 // overflow-conscious code 654 if (cap - MAX_ARRAY_SIZE > 0) { 655 if (p == MAX_ARRAY_SIZE) { 656 throw new OutOfMemoryError(); 657 } 658 cap = MAX_ARRAY_SIZE; 659 } 660 pos = Arrays.copyOf(pos, cap); 661 } 662 pos[p] = j; 663 i = j + targLen; 664 } 665 666 int resultLen; 667 try { 668 resultLen = Math.addExact(valLen, 669 Math.multiplyExact(++p, replLen - targLen)); 670 } catch (ArithmeticException ignored) { 671 throw new OutOfMemoryError(); 672 } 673 if (resultLen == 0) { 674 return ""; 675 } 676 677 byte[] result = newBytesFor(resultLen); 678 int posFrom = 0, posTo = 0; 679 for (int q = 0; q < p; ++q) { 680 int nextPos = pos[q]; 681 if (String.COMPACT_STRINGS && valLat1) { 682 while (posFrom < nextPos) { 683 char c = (char)(value[posFrom++] & 0xff); 684 putChar(result, posTo++, c); 685 } 686 } else { 687 while (posFrom < nextPos) { 688 putChar(result, posTo++, getChar(value, posFrom++)); 689 } 690 } 691 posFrom += targLen; 692 if (String.COMPACT_STRINGS && replLat1) { 693 for (int k = 0; k < replLen; ++k) { 694 char c = (char)(repl[k] & 0xff); 695 putChar(result, posTo++, c); 696 } 697 } else { 698 for (int k = 0; k < replLen; ++k) { 699 putChar(result, posTo++, getChar(repl, k)); 700 } 701 } 702 } 703 if (String.COMPACT_STRINGS && valLat1) { 704 while (posFrom < valLen) { 705 char c = (char)(value[posFrom++] & 0xff); 706 putChar(result, posTo++, c); 707 } 708 } else { 709 while (posFrom < valLen) { 710 putChar(result, posTo++, getChar(value, posFrom++)); 711 } 712 } 713 714 if (String.COMPACT_STRINGS && replLat1 && !targLat1) { 715 // combination 6 716 byte[] lat1Result = compress(result, 0, resultLen); 717 if (lat1Result != null) { 718 return new String(lat1Result, LATIN1); 719 } 720 } 721 return new String(result, UTF16); 722 } 723 724 public static boolean regionMatchesCI(byte[] value, int toffset, 725 byte[] other, int ooffset, int len) { 726 int last = toffset + len; 727 assert toffset >= 0 && ooffset >= 0; 728 assert ooffset + len <= length(other); 729 assert last <= length(value); 730 while (toffset < last) { 731 char c1 = getChar(value, toffset++); 732 char c2 = getChar(other, ooffset++); 733 if (c1 == c2) { 734 continue; 735 } 736 // try converting both characters to uppercase. 737 // If the results match, then the comparison scan should 738 // continue. 739 char u1 = Character.toUpperCase(c1); 740 char u2 = Character.toUpperCase(c2); 741 if (u1 == u2) { 742 continue; 743 } 744 // Unfortunately, conversion to uppercase does not work properly 745 // for the Georgian alphabet, which has strange rules about case 746 // conversion. So we need to make one last check before 747 // exiting. 748 if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 749 continue; 750 } 751 return false; 752 } 753 return true; 754 } 755 756 public static boolean regionMatchesCI_Latin1(byte[] value, int toffset, 757 byte[] other, int ooffset, 758 int len) { 759 return StringLatin1.regionMatchesCI_UTF16(other, ooffset, value, toffset, len); 760 } 761 762 public static String toLowerCase(String str, byte[] value, Locale locale) { 763 if (locale == null) { 764 throw new NullPointerException(); 765 } 766 int first; 767 boolean hasSurr = false; 768 final int len = value.length >> 1; 769 770 // Now check if there are any characters that need to be changed, or are surrogate 771 for (first = 0 ; first < len; first++) { 772 int cp = (int)getChar(value, first); 773 if (Character.isSurrogate((char)cp)) { 774 hasSurr = true; 775 break; 776 } 777 if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR 778 break; 779 } 780 } 781 if (first == len) 782 return str; 783 byte[] result = new byte[value.length]; 784 System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few 785 // lowerCase characters. 786 String lang = locale.getLanguage(); 787 if (lang == "tr" || lang == "az" || lang == "lt") { 788 return toLowerCaseEx(str, value, result, first, locale, true); 789 } 790 if (hasSurr) { 791 return toLowerCaseEx(str, value, result, first, locale, false); 792 } 793 int bits = 0; 794 for (int i = first; i < len; i++) { 795 int cp = (int)getChar(value, i); 796 if (cp == '\u03A3' || // GREEK CAPITAL LETTER SIGMA 797 Character.isSurrogate((char)cp)) { 798 return toLowerCaseEx(str, value, result, i, locale, false); 799 } 800 if (cp == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE 801 return toLowerCaseEx(str, value, result, i, locale, true); 802 } 803 cp = Character.toLowerCase(cp); 804 if (!Character.isBmpCodePoint(cp)) { 805 return toLowerCaseEx(str, value, result, i, locale, false); 806 } 807 bits |= cp; 808 putChar(result, i, cp); 809 } 810 if (bits > 0xFF) { 811 return new String(result, UTF16); 812 } else { 813 return newString(result, 0, len); 814 } 815 } 816 817 private static String toLowerCaseEx(String str, byte[] value, 818 byte[] result, int first, Locale locale, 819 boolean localeDependent) { 820 assert(result.length == value.length); 821 assert(first >= 0); 822 int resultOffset = first; 823 int length = value.length >> 1; 824 int srcCount; 825 for (int i = first; i < length; i += srcCount) { 826 int srcChar = getChar(value, i); 827 int lowerChar; 828 char[] lowerCharArray; 829 srcCount = 1; 830 if (Character.isSurrogate((char)srcChar)) { 831 srcChar = codePointAt(value, i, length); 832 srcCount = Character.charCount(srcChar); 833 } 834 if (localeDependent || 835 srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA 836 srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE 837 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale); 838 } else { 839 lowerChar = Character.toLowerCase(srcChar); 840 } 841 if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp 842 putChar(result, resultOffset++, lowerChar); 843 } else { 844 if (lowerChar == Character.ERROR) { 845 lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale); 846 } else { 847 lowerCharArray = Character.toChars(lowerChar); 848 } 849 /* Grow result if needed */ 850 int mapLen = lowerCharArray.length; 851 if (mapLen > srcCount) { 852 byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount); 853 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 854 result = result2; 855 } 856 assert resultOffset >= 0; 857 assert resultOffset + mapLen <= length(result); 858 for (int x = 0; x < mapLen; ++x) { 859 putChar(result, resultOffset++, lowerCharArray[x]); 860 } 861 } 862 } 863 return newString(result, 0, resultOffset); 864 } 865 866 public static String toUpperCase(String str, byte[] value, Locale locale) { 867 if (locale == null) { 868 throw new NullPointerException(); 869 } 870 int first; 871 boolean hasSurr = false; 872 final int len = value.length >> 1; 873 874 // Now check if there are any characters that need to be changed, or are surrogate 875 for (first = 0 ; first < len; first++) { 876 int cp = (int)getChar(value, first); 877 if (Character.isSurrogate((char)cp)) { 878 hasSurr = true; 879 break; 880 } 881 if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR 882 break; 883 } 884 } 885 if (first == len) { 886 return str; 887 } 888 byte[] result = new byte[value.length]; 889 System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few 890 // upperCase characters. 891 String lang = locale.getLanguage(); 892 if (lang == "tr" || lang == "az" || lang == "lt") { 893 return toUpperCaseEx(str, value, result, first, locale, true); 894 } 895 if (hasSurr) { 896 return toUpperCaseEx(str, value, result, first, locale, false); 897 } 898 int bits = 0; 899 for (int i = first; i < len; i++) { 900 int cp = (int)getChar(value, i); 901 if (Character.isSurrogate((char)cp)) { 902 return toUpperCaseEx(str, value, result, i, locale, false); 903 } 904 cp = Character.toUpperCaseEx(cp); 905 if (!Character.isBmpCodePoint(cp)) { // Character.ERROR is not bmp 906 return toUpperCaseEx(str, value, result, i, locale, false); 907 } 908 bits |= cp; 909 putChar(result, i, cp); 910 } 911 if (bits > 0xFF) { 912 return new String(result, UTF16); 913 } else { 914 return newString(result, 0, len); 915 } 916 } 917 918 private static String toUpperCaseEx(String str, byte[] value, 919 byte[] result, int first, 920 Locale locale, boolean localeDependent) 921 { 922 assert(result.length == value.length); 923 assert(first >= 0); 924 int resultOffset = first; 925 int length = value.length >> 1; 926 int srcCount; 927 for (int i = first; i < length; i += srcCount) { 928 int srcChar = getChar(value, i); 929 int upperChar; 930 char[] upperCharArray; 931 srcCount = 1; 932 if (Character.isSurrogate((char)srcChar)) { 933 srcChar = codePointAt(value, i, length); 934 srcCount = Character.charCount(srcChar); 935 } 936 if (localeDependent) { 937 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale); 938 } else { 939 upperChar = Character.toUpperCaseEx(srcChar); 940 } 941 if (Character.isBmpCodePoint(upperChar)) { 942 putChar(result, resultOffset++, upperChar); 943 } else { 944 if (upperChar == Character.ERROR) { 945 if (localeDependent) { 946 upperCharArray = 947 ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale); 948 } else { 949 upperCharArray = Character.toUpperCaseCharArray(srcChar); 950 } 951 } else { 952 upperCharArray = Character.toChars(upperChar); 953 } 954 /* Grow result if needed */ 955 int mapLen = upperCharArray.length; 956 if (mapLen > srcCount) { 957 byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount); 958 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 959 result = result2; 960 } 961 assert resultOffset >= 0; 962 assert resultOffset + mapLen <= length(result); 963 for (int x = 0; x < mapLen; ++x) { 964 putChar(result, resultOffset++, upperCharArray[x]); 965 } 966 } 967 } 968 return newString(result, 0, resultOffset); 969 } 970 971 public static String trim(byte[] value) { 972 int length = value.length >> 1; 973 int len = length; 974 int st = 0; 975 while (st < len && getChar(value, st) <= ' ') { 976 st++; 977 } 978 while (st < len && getChar(value, len - 1) <= ' ') { 979 len--; 980 } 981 return ((st > 0) || (len < length )) ? 982 new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) : 983 null; 984 } 985 986 public static int indexOfNonWhitespace(byte[] value) { 987 int length = value.length >> 1; 988 int left = 0; 989 while (left < length) { 990 int codepoint = codePointAt(value, left, length); 991 if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) { 992 break; 993 } 994 left += Character.charCount(codepoint); 995 } 996 return left; 997 } 998 999 public static int lastIndexOfNonWhitespace(byte[] value) { 1000 int length = value.length >>> 1; 1001 int right = length; 1002 while (0 < right) { 1003 int codepoint = codePointBefore(value, right); 1004 if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) { 1005 break; 1006 } 1007 right -= Character.charCount(codepoint); 1008 } 1009 return right; 1010 } 1011 1012 public static String strip(byte[] value) { 1013 int length = value.length >>> 1; 1014 int left = indexOfNonWhitespace(value); 1015 if (left == length) { 1016 return ""; 1017 } 1018 int right = lastIndexOfNonWhitespace(value); 1019 boolean ifChanged = (left > 0) || (right < length); 1020 return ifChanged ? newString(value, left, right - left) : null; 1021 } 1022 1023 public static String stripLeading(byte[] value) { 1024 int length = value.length >>> 1; 1025 int left = indexOfNonWhitespace(value); 1026 if (left == length) { 1027 return ""; 1028 } 1029 return (left != 0) ? newString(value, left, length - left) : null; 1030 } 1031 1032 public static String stripTrailing(byte[] value) { 1033 int length = value.length >>> 1; 1034 int right = lastIndexOfNonWhitespace(value); 1035 if (right == 0) { 1036 return ""; 1037 } 1038 return (right != length) ? newString(value, 0, right) : null; 1039 } 1040 1041 private final static class LinesSpliterator implements Spliterator<String> { 1042 private byte[] value; 1043 private int index; // current index, modified on advance/split 1044 private final int fence; // one past last index 1045 1046 private LinesSpliterator(byte[] value, int start, int length) { 1047 this.value = value; 1048 this.index = start; 1049 this.fence = start + length; 1050 } 1051 1052 private int indexOfLineSeparator(int start) { 1053 for (int current = start; current < fence; current++) { 1054 char ch = getChar(value, current); 1055 if (ch == '\n' || ch == '\r') { 1056 return current; 1057 } 1058 } 1059 return fence; 1060 } 1061 1062 private int skipLineSeparator(int start) { 1063 if (start < fence) { 1064 if (getChar(value, start) == '\r') { 1065 int next = start + 1; 1066 if (next < fence && getChar(value, next) == '\n') { 1067 return next + 1; 1068 } 1069 } 1070 return start + 1; 1071 } 1072 return fence; 1073 } 1074 1075 private String next() { 1076 int start = index; 1077 int end = indexOfLineSeparator(start); 1078 index = skipLineSeparator(end); 1079 return newString(value, start, end - start); 1080 } 1081 1082 @Override 1083 public boolean tryAdvance(Consumer<? super String> action) { 1084 if (action == null) { 1085 throw new NullPointerException("tryAdvance action missing"); 1086 } 1087 if (index != fence) { 1088 action.accept(next()); 1089 return true; 1090 } 1091 return false; 1092 } 1093 1094 @Override 1095 public void forEachRemaining(Consumer<? super String> action) { 1096 if (action == null) { 1097 throw new NullPointerException("forEachRemaining action missing"); 1098 } 1099 while (index != fence) { 1100 action.accept(next()); 1101 } 1102 } 1103 1104 @Override 1105 public Spliterator<String> trySplit() { 1106 int half = (fence + index) >>> 1; 1107 int mid = skipLineSeparator(indexOfLineSeparator(half)); 1108 if (mid < fence) { 1109 int start = index; 1110 index = mid; 1111 return new LinesSpliterator(value, start, mid - start); 1112 } 1113 return null; 1114 } 1115 1116 @Override 1117 public long estimateSize() { 1118 return fence - index + 1; 1119 } 1120 1121 @Override 1122 public int characteristics() { 1123 return Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL; 1124 } 1125 1126 static LinesSpliterator spliterator(byte[] value) { 1127 return new LinesSpliterator(value, 0, value.length >>> 1); 1128 } 1129 1130 static LinesSpliterator spliterator(byte[] value, int leading, int trailing) { 1131 int length = value.length >>> 1; 1132 int left = 0; 1133 int index; 1134 for (int l = 0; l < leading; l++) { 1135 index = skipBlankForward(value, left, length); 1136 if (index == left) { 1137 break; 1138 } 1139 left = index; 1140 } 1141 int right = length; 1142 for (int t = 0; t < trailing; t++) { 1143 index = skipBlankBackward(value, left, right); 1144 if (index == right) { 1145 break; 1146 } 1147 right = index; 1148 } 1149 return new LinesSpliterator(value, left, right - left); 1150 } 1151 1152 private static int skipBlankForward(byte[] value, int start, int length) { 1153 int index = start; 1154 while (index < length) { 1155 char ch = getChar(value, index++); 1156 if (ch == '\n') { 1157 return index; 1158 } 1159 if (ch == '\r') { 1160 if (index < length && getChar(value, index) == '\n') { 1161 return index + 1; 1162 } 1163 return index; 1164 } 1165 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) { 1166 return start; 1167 } 1168 } 1169 return length; 1170 } 1171 1172 private static int skipBlankBackward(byte[] value, int start, int fence) { 1173 int index = fence; 1174 if (start < index && getChar(value, index - 1) == '\n') { 1175 index--; 1176 } 1177 if (start < index && getChar(value, index - 1) == '\r') { 1178 index--; 1179 } 1180 while (start < index) { 1181 char ch = getChar(value, --index); 1182 if (ch == '\r' || ch == '\n') { 1183 return index + 1; 1184 } 1185 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) { 1186 return fence; 1187 } 1188 } 1189 return start; 1190 } 1191 } 1192 1193 static Stream<String> lines(byte[] value, int leading, int trailing) { 1194 if (leading == 0 && trailing == 0) { 1195 return StreamSupport.stream(LinesSpliterator.spliterator(value), false); 1196 } else { 1197 return StreamSupport.stream(LinesSpliterator.spliterator(value, leading, trailing), false); 1198 } 1199 } 1200 1201 private static void putChars(byte[] val, int index, char[] str, int off, int end) { 1202 while (off < end) { 1203 putChar(val, index++, str[off++]); 1204 } 1205 } 1206 1207 public static String newString(byte[] val, int index, int len) { 1208 if (String.COMPACT_STRINGS) { 1209 byte[] buf = compress(val, index, len); 1210 if (buf != null) { 1211 return new String(buf, LATIN1); 1212 } 1213 } 1214 int last = index + len; 1215 return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16); 1216 } 1217 1218 public static void fillNull(byte[] val, int index, int end) { 1219 Arrays.fill(val, index << 1, end << 1, (byte)0); 1220 } 1221 1222 static class CharsSpliterator implements Spliterator.OfInt { 1223 private final byte[] array; 1224 private int index; // current index, modified on advance/split 1225 private final int fence; // one past last index 1226 private final int cs; 1227 1228 CharsSpliterator(byte[] array, int acs) { 1229 this(array, 0, array.length >> 1, acs); 1230 } 1231 1232 CharsSpliterator(byte[] array, int origin, int fence, int acs) { 1233 this.array = array; 1234 this.index = origin; 1235 this.fence = fence; 1236 this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED 1237 | Spliterator.SUBSIZED; 1238 } 1239 1240 @Override 1241 public OfInt trySplit() { 1242 int lo = index, mid = (lo + fence) >>> 1; 1243 return (lo >= mid) 1244 ? null 1245 : new CharsSpliterator(array, lo, index = mid, cs); 1246 } 1247 1248 @Override 1249 public void forEachRemaining(IntConsumer action) { 1250 byte[] a; int i, hi; // hoist accesses and checks from loop 1251 if (action == null) 1252 throw new NullPointerException(); 1253 if (((a = array).length >> 1) >= (hi = fence) && 1254 (i = index) >= 0 && i < (index = hi)) { 1255 do { 1256 action.accept(charAt(a, i)); 1257 } while (++i < hi); 1258 } 1259 } 1260 1261 @Override 1262 public boolean tryAdvance(IntConsumer action) { 1263 if (action == null) 1264 throw new NullPointerException(); 1265 int i = index; 1266 if (i >= 0 && i < fence) { 1267 action.accept(charAt(array, i)); 1268 index++; 1269 return true; 1270 } 1271 return false; 1272 } 1273 1274 @Override 1275 public long estimateSize() { return (long)(fence - index); } 1276 1277 @Override 1278 public int characteristics() { 1279 return cs; 1280 } 1281 } 1282 1283 static class CodePointsSpliterator implements Spliterator.OfInt { 1284 private final byte[] array; 1285 private int index; // current index, modified on advance/split 1286 private final int fence; // one past last index 1287 private final int cs; 1288 1289 CodePointsSpliterator(byte[] array, int acs) { 1290 this(array, 0, array.length >> 1, acs); 1291 } 1292 1293 CodePointsSpliterator(byte[] array, int origin, int fence, int acs) { 1294 this.array = array; 1295 this.index = origin; 1296 this.fence = fence; 1297 this.cs = acs | Spliterator.ORDERED; 1298 } 1299 1300 @Override 1301 public OfInt trySplit() { 1302 int lo = index, mid = (lo + fence) >>> 1; 1303 if (lo >= mid) 1304 return null; 1305 1306 int midOneLess; 1307 // If the mid-point intersects a surrogate pair 1308 if (Character.isLowSurrogate(charAt(array, mid)) && 1309 Character.isHighSurrogate(charAt(array, midOneLess = (mid -1)))) { 1310 // If there is only one pair it cannot be split 1311 if (lo >= midOneLess) 1312 return null; 1313 // Shift the mid-point to align with the surrogate pair 1314 return new CodePointsSpliterator(array, lo, index = midOneLess, cs); 1315 } 1316 return new CodePointsSpliterator(array, lo, index = mid, cs); 1317 } 1318 1319 @Override 1320 public void forEachRemaining(IntConsumer action) { 1321 byte[] a; int i, hi; // hoist accesses and checks from loop 1322 if (action == null) 1323 throw new NullPointerException(); 1324 if (((a = array).length >> 1) >= (hi = fence) && 1325 (i = index) >= 0 && i < (index = hi)) { 1326 do { 1327 i = advance(a, i, hi, action); 1328 } while (i < hi); 1329 } 1330 } 1331 1332 @Override 1333 public boolean tryAdvance(IntConsumer action) { 1334 if (action == null) 1335 throw new NullPointerException(); 1336 if (index >= 0 && index < fence) { 1337 index = advance(array, index, fence, action); 1338 return true; 1339 } 1340 return false; 1341 } 1342 1343 // Advance one code point from the index, i, and return the next 1344 // index to advance from 1345 private static int advance(byte[] a, int i, int hi, IntConsumer action) { 1346 char c1 = charAt(a, i++); 1347 int cp = c1; 1348 if (Character.isHighSurrogate(c1) && i < hi) { 1349 char c2 = charAt(a, i); 1350 if (Character.isLowSurrogate(c2)) { 1351 i++; 1352 cp = Character.toCodePoint(c1, c2); 1353 } 1354 } 1355 action.accept(cp); 1356 return i; 1357 } 1358 1359 @Override 1360 public long estimateSize() { return (long)(fence - index); } 1361 1362 @Override 1363 public int characteristics() { 1364 return cs; 1365 } 1366 } 1367 1368 //////////////////////////////////////////////////////////////// 1369 1370 public static void putCharSB(byte[] val, int index, int c) { 1371 checkIndex(index, val); 1372 putChar(val, index, c); 1373 } 1374 1375 public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) { 1376 checkBoundsBeginEnd(index, index + end - off, val); 1377 putChars(val, index, ca, off, end); 1378 } 1379 1380 public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) { 1381 checkBoundsBeginEnd(index, index + end - off, val); 1382 for (int i = off; i < end; i++) { 1383 putChar(val, index++, s.charAt(i)); 1384 } 1385 } 1386 1387 public static int codePointAtSB(byte[] val, int index, int end) { 1388 return codePointAt(val, index, end, true /* checked */); 1389 } 1390 1391 public static int codePointBeforeSB(byte[] val, int index) { 1392 return codePointBefore(val, index, true /* checked */); 1393 } 1394 1395 public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) { 1396 return codePointCount(val, beginIndex, endIndex, true /* checked */); 1397 } 1398 1399 public static int getChars(int i, int begin, int end, byte[] value) { 1400 checkBoundsBeginEnd(begin, end, value); 1401 int pos = getChars(i, end, value); 1402 assert begin == pos; 1403 return pos; 1404 } 1405 1406 public static int getChars(long l, int begin, int end, byte[] value) { 1407 checkBoundsBeginEnd(begin, end, value); 1408 int pos = getChars(l, end, value); 1409 assert begin == pos; 1410 return pos; 1411 } 1412 1413 public static boolean contentEquals(byte[] v1, byte[] v2, int len) { 1414 checkBoundsOffCount(0, len, v2); 1415 for (int i = 0; i < len; i++) { 1416 if ((char)(v1[i] & 0xff) != getChar(v2, i)) { 1417 return false; 1418 } 1419 } 1420 return true; 1421 } 1422 1423 public static boolean contentEquals(byte[] value, CharSequence cs, int len) { 1424 checkOffset(len, value); 1425 for (int i = 0; i < len; i++) { 1426 if (getChar(value, i) != cs.charAt(i)) { 1427 return false; 1428 } 1429 } 1430 return true; 1431 } 1432 1433 public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { 1434 int end = i + 4; 1435 checkBoundsBeginEnd(i, end, value); 1436 putChar(value, i++, c1); 1437 putChar(value, i++, c2); 1438 putChar(value, i++, c3); 1439 putChar(value, i++, c4); 1440 assert(i == end); 1441 return end; 1442 } 1443 1444 public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { 1445 int end = i + 5; 1446 checkBoundsBeginEnd(i, end, value); 1447 putChar(value, i++, c1); 1448 putChar(value, i++, c2); 1449 putChar(value, i++, c3); 1450 putChar(value, i++, c4); 1451 putChar(value, i++, c5); 1452 assert(i == end); 1453 return end; 1454 } 1455 1456 public static char charAt(byte[] value, int index) { 1457 checkIndex(index, value); 1458 return getChar(value, index); 1459 } 1460 1461 public static void reverse(byte[] val, int count) { 1462 checkOffset(count, val); 1463 int n = count - 1; 1464 boolean hasSurrogates = false; 1465 for (int j = (n-1) >> 1; j >= 0; j--) { 1466 int k = n - j; 1467 char cj = getChar(val, j); 1468 char ck = getChar(val, k); 1469 putChar(val, j, ck); 1470 putChar(val, k, cj); 1471 if (Character.isSurrogate(cj) || 1472 Character.isSurrogate(ck)) { 1473 hasSurrogates = true; 1474 } 1475 } 1476 if (hasSurrogates) { 1477 reverseAllValidSurrogatePairs(val, count); 1478 } 1479 } 1480 1481 /** Outlined helper method for reverse() */ 1482 private static void reverseAllValidSurrogatePairs(byte[] val, int count) { 1483 for (int i = 0; i < count - 1; i++) { 1484 char c2 = getChar(val, i); 1485 if (Character.isLowSurrogate(c2)) { 1486 char c1 = getChar(val, i + 1); 1487 if (Character.isHighSurrogate(c1)) { 1488 putChar(val, i++, c1); 1489 putChar(val, i, c2); 1490 } 1491 } 1492 } 1493 } 1494 1495 // inflatedCopy byte[] -> byte[] 1496 public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { 1497 // We need a range check here because 'putChar' has no checks 1498 checkBoundsOffCount(dstOff, len, dst); 1499 for (int i = 0; i < len; i++) { 1500 putChar(dst, dstOff++, src[srcOff++] & 0xff); 1501 } 1502 } 1503 1504 // srcCoder == UTF16 && tgtCoder == LATIN1 1505 public static int lastIndexOfLatin1(byte[] src, int srcCount, 1506 byte[] tgt, int tgtCount, int fromIndex) { 1507 assert fromIndex >= 0; 1508 assert tgtCount > 0; 1509 assert tgtCount <= tgt.length; 1510 int min = tgtCount - 1; 1511 int i = min + fromIndex; 1512 int strLastIndex = tgtCount - 1; 1513 1514 char strLastChar = (char)(tgt[strLastIndex] & 0xff); 1515 1516 checkIndex(i, src); 1517 1518 startSearchForLastChar: 1519 while (true) { 1520 while (i >= min && getChar(src, i) != strLastChar) { 1521 i--; 1522 } 1523 if (i < min) { 1524 return -1; 1525 } 1526 int j = i - 1; 1527 int start = j - strLastIndex; 1528 int k = strLastIndex - 1; 1529 while (j > start) { 1530 if (getChar(src, j--) != (tgt[k--] & 0xff)) { 1531 i--; 1532 continue startSearchForLastChar; 1533 } 1534 } 1535 return start + 1; 1536 } 1537 } 1538 1539 //////////////////////////////////////////////////////////////// 1540 1541 private static native boolean isBigEndian(); 1542 1543 static final int HI_BYTE_SHIFT; 1544 static final int LO_BYTE_SHIFT; 1545 static { 1546 if (isBigEndian()) { 1547 HI_BYTE_SHIFT = 8; 1548 LO_BYTE_SHIFT = 0; 1549 } else { 1550 HI_BYTE_SHIFT = 0; 1551 LO_BYTE_SHIFT = 8; 1552 } 1553 } 1554 1555 static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; 1556 1557 1558 /** 1559 * The maximum size of array to allocate (unless necessary). 1560 * Some VMs reserve some header words in an array. 1561 * Attempts to allocate larger arrays may result in 1562 * OutOfMemoryError: Requested array size exceeds VM limit 1563 */ 1564 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 1565 1566 // Used by trusted callers. Assumes all necessary bounds checks have 1567 // been done by the caller. 1568 1569 /** 1570 * This is a variant of {@link Integer#getChars(int, int, byte[])}, but for 1571 * UTF-16 coder. 1572 * 1573 * @param i value to convert 1574 * @param index next index, after the least significant digit 1575 * @param buf target buffer, UTF16-coded. 1576 * @return index of the most significant digit or minus sign, if present 1577 */ 1578 static int getChars(int i, int index, byte[] buf) { 1579 int q, r; 1580 int charPos = index; 1581 1582 boolean negative = (i < 0); 1583 if (!negative) { 1584 i = -i; 1585 } 1586 1587 // Get 2 digits/iteration using ints 1588 while (i <= -100) { 1589 q = i / 100; 1590 r = (q * 100) - i; 1591 i = q; 1592 putChar(buf, --charPos, Integer.DigitOnes[r]); 1593 putChar(buf, --charPos, Integer.DigitTens[r]); 1594 } 1595 1596 // We know there are at most two digits left at this point. 1597 q = i / 10; 1598 r = (q * 10) - i; 1599 putChar(buf, --charPos, '0' + r); 1600 1601 // Whatever left is the remaining digit. 1602 if (q < 0) { 1603 putChar(buf, --charPos, '0' - q); 1604 } 1605 1606 if (negative) { 1607 putChar(buf, --charPos, '-'); 1608 } 1609 return charPos; 1610 } 1611 1612 /** 1613 * This is a variant of {@link Long#getChars(long, int, byte[])}, but for 1614 * UTF-16 coder. 1615 * 1616 * @param i value to convert 1617 * @param index next index, after the least significant digit 1618 * @param buf target buffer, UTF16-coded. 1619 * @return index of the most significant digit or minus sign, if present 1620 */ 1621 static int getChars(long i, int index, byte[] buf) { 1622 long q; 1623 int r; 1624 int charPos = index; 1625 1626 boolean negative = (i < 0); 1627 if (!negative) { 1628 i = -i; 1629 } 1630 1631 // Get 2 digits/iteration using longs until quotient fits into an int 1632 while (i <= Integer.MIN_VALUE) { 1633 q = i / 100; 1634 r = (int)((q * 100) - i); 1635 i = q; 1636 putChar(buf, --charPos, Integer.DigitOnes[r]); 1637 putChar(buf, --charPos, Integer.DigitTens[r]); 1638 } 1639 1640 // Get 2 digits/iteration using ints 1641 int q2; 1642 int i2 = (int)i; 1643 while (i2 <= -100) { 1644 q2 = i2 / 100; 1645 r = (q2 * 100) - i2; 1646 i2 = q2; 1647 putChar(buf, --charPos, Integer.DigitOnes[r]); 1648 putChar(buf, --charPos, Integer.DigitTens[r]); 1649 } 1650 1651 // We know there are at most two digits left at this point. 1652 q2 = i2 / 10; 1653 r = (q2 * 10) - i2; 1654 putChar(buf, --charPos, '0' + r); 1655 1656 // Whatever left is the remaining digit. 1657 if (q2 < 0) { 1658 putChar(buf, --charPos, '0' - q2); 1659 } 1660 1661 if (negative) { 1662 putChar(buf, --charPos, '-'); 1663 } 1664 return charPos; 1665 } 1666 // End of trusted methods. 1667 1668 public static void checkIndex(int off, byte[] val) { 1669 String.checkIndex(off, length(val)); 1670 } 1671 1672 public static void checkOffset(int off, byte[] val) { 1673 String.checkOffset(off, length(val)); 1674 } 1675 1676 public static void checkBoundsBeginEnd(int begin, int end, byte[] val) { 1677 String.checkBoundsBeginEnd(begin, end, length(val)); 1678 } 1679 1680 public static void checkBoundsOffCount(int offset, int count, byte[] val) { 1681 String.checkBoundsOffCount(offset, count, length(val)); 1682 } 1683 1684 }