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