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.Objects; 31 import java.util.Spliterator; 32 import java.util.function.Consumer; 33 import java.util.function.IntConsumer; 34 import java.util.stream.IntStream; 35 import java.util.stream.Stream; 36 import java.util.stream.StreamSupport; 37 import jdk.internal.HotSpotIntrinsicCandidate; 38 39 import static java.lang.String.LATIN1; 40 import static java.lang.String.UTF16; 41 import static java.lang.String.checkOffset; 42 43 final class StringLatin1 { 44 charAt(byte[] value, int index)45 public static char charAt(byte[] value, int index) { 46 if (index < 0 || index >= value.length) { 47 throw new StringIndexOutOfBoundsException(index); 48 } 49 return (char)(value[index] & 0xff); 50 } 51 canEncode(int cp)52 public static boolean canEncode(int cp) { 53 return cp >>> 8 == 0; 54 } 55 length(byte[] value)56 public static int length(byte[] value) { 57 return value.length; 58 } 59 codePointAt(byte[] value, int index, int end)60 public static int codePointAt(byte[] value, int index, int end) { 61 return value[index] & 0xff; 62 } 63 codePointBefore(byte[] value, int index)64 public static int codePointBefore(byte[] value, int index) { 65 return value[index - 1] & 0xff; 66 } 67 codePointCount(byte[] value, int beginIndex, int endIndex)68 public static int codePointCount(byte[] value, int beginIndex, int endIndex) { 69 return endIndex - beginIndex; 70 } 71 toChars(byte[] value)72 public static char[] toChars(byte[] value) { 73 char[] dst = new char[value.length]; 74 inflate(value, 0, dst, 0, value.length); 75 return dst; 76 } 77 inflate(byte[] value, int off, int len)78 public static byte[] inflate(byte[] value, int off, int len) { 79 byte[] ret = StringUTF16.newBytesFor(len); 80 inflate(value, off, ret, 0, len); 81 return ret; 82 } 83 getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin)84 public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) { 85 inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); 86 } 87 getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin)88 public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) { 89 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); 90 } 91 92 @HotSpotIntrinsicCandidate equals(byte[] value, byte[] other)93 public static boolean equals(byte[] value, byte[] other) { 94 if (value.length == other.length) { 95 for (int i = 0; i < value.length; i++) { 96 if (value[i] != other[i]) { 97 return false; 98 } 99 } 100 return true; 101 } 102 return false; 103 } 104 105 @HotSpotIntrinsicCandidate compareTo(byte[] value, byte[] other)106 public static int compareTo(byte[] value, byte[] other) { 107 int len1 = value.length; 108 int len2 = other.length; 109 return compareTo(value, other, len1, len2); 110 } 111 compareTo(byte[] value, byte[] other, int len1, int len2)112 public static int compareTo(byte[] value, byte[] other, int len1, int len2) { 113 int lim = Math.min(len1, len2); 114 for (int k = 0; k < lim; k++) { 115 if (value[k] != other[k]) { 116 return getChar(value, k) - getChar(other, k); 117 } 118 } 119 return len1 - len2; 120 } 121 122 @HotSpotIntrinsicCandidate compareToUTF16(byte[] value, byte[] other)123 public static int compareToUTF16(byte[] value, byte[] other) { 124 int len1 = length(value); 125 int len2 = StringUTF16.length(other); 126 return compareToUTF16Values(value, other, len1, len2); 127 } 128 129 /* 130 * Checks the boundary and then compares the byte arrays. 131 */ compareToUTF16(byte[] value, byte[] other, int len1, int len2)132 public static int compareToUTF16(byte[] value, byte[] other, int len1, int len2) { 133 checkOffset(len1, length(value)); 134 checkOffset(len2, StringUTF16.length(other)); 135 136 return compareToUTF16Values(value, other, len1, len2); 137 } 138 compareToUTF16Values(byte[] value, byte[] other, int len1, int len2)139 private static int compareToUTF16Values(byte[] value, byte[] other, int len1, int len2) { 140 int lim = Math.min(len1, len2); 141 for (int k = 0; k < lim; k++) { 142 char c1 = getChar(value, k); 143 char c2 = StringUTF16.getChar(other, k); 144 if (c1 != c2) { 145 return c1 - c2; 146 } 147 } 148 return len1 - len2; 149 } 150 compareToCI(byte[] value, byte[] other)151 public static int compareToCI(byte[] value, byte[] other) { 152 int len1 = value.length; 153 int len2 = other.length; 154 int lim = Math.min(len1, len2); 155 for (int k = 0; k < lim; k++) { 156 if (value[k] != other[k]) { 157 // Android-changed: libcore doesn't have CharacterDataLatin1. 158 // char c1 = (char) CharacterDataLatin1.instance.toUpperCase(getChar(value, k)); 159 // char c2 = (char) CharacterDataLatin1.instance.toUpperCase(getChar(other, k)); 160 char c1 = (char) Character.toUpperCase(getChar(value, k)); 161 char c2 = (char) Character.toUpperCase(getChar(other, k)); 162 if (c1 != c2) { 163 c1 = Character.toLowerCase(c1); 164 c2 = Character.toLowerCase(c2); 165 if (c1 != c2) { 166 return c1 - c2; 167 } 168 } 169 } 170 } 171 return len1 - len2; 172 } 173 compareToCI_UTF16(byte[] value, byte[] other)174 public static int compareToCI_UTF16(byte[] value, byte[] other) { 175 int len1 = length(value); 176 int len2 = StringUTF16.length(other); 177 int lim = Math.min(len1, len2); 178 for (int k = 0; k < lim; k++) { 179 char c1 = getChar(value, k); 180 char c2 = StringUTF16.getChar(other, k); 181 if (c1 != c2) { 182 c1 = Character.toUpperCase(c1); 183 c2 = Character.toUpperCase(c2); 184 if (c1 != c2) { 185 c1 = Character.toLowerCase(c1); 186 c2 = Character.toLowerCase(c2); 187 if (c1 != c2) { 188 return c1 - c2; 189 } 190 } 191 } 192 } 193 return len1 - len2; 194 } 195 hashCode(byte[] value)196 public static int hashCode(byte[] value) { 197 int h = 0; 198 for (byte v : value) { 199 h = 31 * h + (v & 0xff); 200 } 201 return h; 202 } 203 indexOf(byte[] value, int ch, int fromIndex)204 public static int indexOf(byte[] value, int ch, int fromIndex) { 205 if (!canEncode(ch)) { 206 return -1; 207 } 208 int max = value.length; 209 if (fromIndex < 0) { 210 fromIndex = 0; 211 } else if (fromIndex >= max) { 212 // Note: fromIndex might be near -1>>>1. 213 return -1; 214 } 215 byte c = (byte)ch; 216 for (int i = fromIndex; i < max; i++) { 217 if (value[i] == c) { 218 return i; 219 } 220 } 221 return -1; 222 } 223 224 // Android-removed: Remove unused code. 225 /* 226 @HotSpotIntrinsicCandidate 227 public static int indexOf(byte[] value, byte[] str) { 228 if (str.length == 0) { 229 return 0; 230 } 231 if (value.length == 0) { 232 return -1; 233 } 234 return indexOf(value, value.length, str, str.length, 0); 235 } 236 */ 237 238 @HotSpotIntrinsicCandidate 239 // Android-changed: libcore doesn't store String as Latin1 or UTF16 byte[] field. 240 // public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { indexOf(byte[] value, int valueCount, String str, int strCount, int fromIndex)241 public static int indexOf(byte[] value, int valueCount, String str, int strCount, int fromIndex) { 242 // byte first = str[0]; 243 byte first = (byte) str.charAt(0); 244 int max = (valueCount - strCount); 245 for (int i = fromIndex; i <= max; i++) { 246 // Look for first character. 247 if (value[i] != first) { 248 while (++i <= max && value[i] != first); 249 } 250 // Found first character, now look at the rest of value 251 if (i <= max) { 252 int j = i + 1; 253 int end = j + strCount - 1; 254 // Android-changed: Use charAt() because libcore doesn't store byte[] in java level. 255 // for (int k = 1; j < end && value[j] == str[k]; j++, k++); 256 for (int k = 1; j < end && value[j] == ((byte) str.charAt(k)); j++, k++); 257 if (j == end) { 258 // Found whole string. 259 return i; 260 } 261 } 262 } 263 return -1; 264 } 265 lastIndexOf(byte[] src, int srcCount, String tgt, int tgtCount, int fromIndex)266 public static int lastIndexOf(byte[] src, int srcCount, 267 // Android-changed: String has no byte[] field in libcore. 268 // byte[] tgt, int tgtCount, int fromIndex) { 269 String tgt, int tgtCount, int fromIndex) { 270 int min = tgtCount - 1; 271 int i = min + fromIndex; 272 int strLastIndex = tgtCount - 1; 273 // char strLastChar = (char)(tgt[strLastIndex] & 0xff); 274 char strLastChar = tgt.charAt(strLastIndex); 275 276 startSearchForLastChar: 277 while (true) { 278 while (i >= min && (src[i] & 0xff) != strLastChar) { 279 i--; 280 } 281 if (i < min) { 282 return -1; 283 } 284 int j = i - 1; 285 int start = j - strLastIndex; 286 int k = strLastIndex - 1; 287 while (j > start) { 288 // Android-changed: Use charAt() because libcore doesn't store byte[] in java level. 289 // if ((src[j--] & 0xff) != (tgt[k--] & 0xff)) { 290 if ((src[j--] & 0xff) != (tgt.charAt(k--) & 0xff)) { 291 i--; 292 continue startSearchForLastChar; 293 } 294 } 295 return start + 1; 296 } 297 } 298 lastIndexOf(final byte[] value, int ch, int fromIndex)299 public static int lastIndexOf(final byte[] value, int ch, int fromIndex) { 300 if (!canEncode(ch)) { 301 return -1; 302 } 303 int off = Math.min(fromIndex, value.length - 1); 304 for (; off >= 0; off--) { 305 if (value[off] == (byte)ch) { 306 return off; 307 } 308 } 309 return -1; 310 } 311 312 // BEGIN Android-removed: Remove unused code. 313 /* 314 public static String replace(byte[] value, char oldChar, char newChar) { 315 if (canEncode(oldChar)) { 316 int len = value.length; 317 int i = -1; 318 while (++i < len) { 319 if (value[i] == (byte)oldChar) { 320 break; 321 } 322 } 323 if (i < len) { 324 if (canEncode(newChar)) { 325 byte buf[] = new byte[len]; 326 for (int j = 0; j < i; j++) { // TBD arraycopy? 327 buf[j] = value[j]; 328 } 329 while (i < len) { 330 byte c = value[i]; 331 buf[i] = (c == (byte)oldChar) ? (byte)newChar : c; 332 i++; 333 } 334 return new String(buf, LATIN1); 335 } else { 336 byte[] buf = StringUTF16.newBytesFor(len); 337 // inflate from latin1 to UTF16 338 inflate(value, 0, buf, 0, i); 339 while (i < len) { 340 char c = (char)(value[i] & 0xff); 341 StringUTF16.putChar(buf, i, (c == oldChar) ? newChar : c); 342 i++; 343 } 344 return new String(buf, UTF16); 345 } 346 } 347 } 348 return null; // for string to return this; 349 } 350 351 // case insensitive 352 public static boolean regionMatchesCI(byte[] value, int toffset, 353 byte[] other, int ooffset, int len) { 354 int last = toffset + len; 355 while (toffset < last) { 356 char c1 = (char)(value[toffset++] & 0xff); 357 char c2 = (char)(other[ooffset++] & 0xff); 358 if (c1 == c2) { 359 continue; 360 } 361 char u1 = Character.toUpperCase(c1); 362 char u2 = Character.toUpperCase(c2); 363 if (u1 == u2) { 364 continue; 365 } 366 if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 367 continue; 368 } 369 return false; 370 } 371 return true; 372 } 373 374 public static boolean regionMatchesCI_UTF16(byte[] value, int toffset, 375 byte[] other, int ooffset, int len) { 376 int last = toffset + len; 377 while (toffset < last) { 378 char c1 = (char)(value[toffset++] & 0xff); 379 char c2 = StringUTF16.getChar(other, ooffset++); 380 if (c1 == c2) { 381 continue; 382 } 383 char u1 = Character.toUpperCase(c1); 384 char u2 = Character.toUpperCase(c2); 385 if (u1 == u2) { 386 continue; 387 } 388 if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 389 continue; 390 } 391 return false; 392 } 393 return true; 394 } 395 396 public static String toLowerCase(String str, byte[] value, Locale locale) { 397 if (locale == null) { 398 throw new NullPointerException(); 399 } 400 int first; 401 final int len = value.length; 402 // Now check if there are any characters that need to be changed, or are surrogate 403 for (first = 0 ; first < len; first++) { 404 int cp = value[first] & 0xff; 405 if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR 406 break; 407 } 408 } 409 if (first == len) 410 return str; 411 String lang = locale.getLanguage(); 412 if (lang == "tr" || lang == "az" || lang == "lt") { 413 return toLowerCaseEx(str, value, first, locale, true); 414 } 415 byte[] result = new byte[len]; 416 System.arraycopy(value, 0, result, 0, first); // Just copy the first few 417 // lowerCase characters. 418 for (int i = first; i < len; i++) { 419 int cp = value[i] & 0xff; 420 cp = Character.toLowerCase(cp); 421 if (!canEncode(cp)) { // not a latin1 character 422 return toLowerCaseEx(str, value, first, locale, false); 423 } 424 result[i] = (byte)cp; 425 } 426 return new String(result, LATIN1); 427 } 428 429 private static String toLowerCaseEx(String str, byte[] value, 430 int first, Locale locale, boolean localeDependent) 431 { 432 byte[] result = StringUTF16.newBytesFor(value.length); 433 int resultOffset = 0; 434 for (int i = 0; i < first; i++) { 435 StringUTF16.putChar(result, resultOffset++, value[i] & 0xff); 436 } 437 for (int i = first; i < value.length; i++) { 438 int srcChar = value[i] & 0xff; 439 int lowerChar; 440 char[] lowerCharArray; 441 if (localeDependent) { 442 lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale); 443 } else { 444 lowerChar = Character.toLowerCase(srcChar); 445 } 446 if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp 447 StringUTF16.putChar(result, resultOffset++, lowerChar); 448 } else { 449 if (lowerChar == Character.ERROR) { 450 lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale); 451 } else { 452 lowerCharArray = Character.toChars(lowerChar); 453 } 454 /* Grow result if needed * 455 int mapLen = lowerCharArray.length; 456 if (mapLen > 1) { 457 byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1); 458 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 459 result = result2; 460 } 461 for (int x = 0; x < mapLen; ++x) { 462 StringUTF16.putChar(result, resultOffset++, lowerCharArray[x]); 463 } 464 } 465 } 466 return StringUTF16.newString(result, 0, resultOffset); 467 } 468 469 public static String toUpperCase(String str, byte[] value, Locale locale) { 470 if (locale == null) { 471 throw new NullPointerException(); 472 } 473 int first; 474 final int len = value.length; 475 476 // Now check if there are any characters that need to be changed, or are surrogate 477 for (first = 0 ; first < len; first++ ) { 478 int cp = value[first] & 0xff; 479 if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR 480 break; 481 } 482 } 483 if (first == len) { 484 return str; 485 } 486 String lang = locale.getLanguage(); 487 if (lang == "tr" || lang == "az" || lang == "lt") { 488 return toUpperCaseEx(str, value, first, locale, true); 489 } 490 byte[] result = new byte[len]; 491 System.arraycopy(value, 0, result, 0, first); // Just copy the first few 492 // upperCase characters. 493 for (int i = first; i < len; i++) { 494 int cp = value[i] & 0xff; 495 cp = Character.toUpperCaseEx(cp); 496 if (!canEncode(cp)) { // not a latin1 character 497 return toUpperCaseEx(str, value, first, locale, false); 498 } 499 result[i] = (byte)cp; 500 } 501 return new String(result, LATIN1); 502 } 503 504 private static String toUpperCaseEx(String str, byte[] value, 505 int first, Locale locale, boolean localeDependent) 506 { 507 byte[] result = StringUTF16.newBytesFor(value.length); 508 int resultOffset = 0; 509 for (int i = 0; i < first; i++) { 510 StringUTF16.putChar(result, resultOffset++, value[i] & 0xff); 511 } 512 for (int i = first; i < value.length; i++) { 513 int srcChar = value[i] & 0xff; 514 int upperChar; 515 char[] upperCharArray; 516 if (localeDependent) { 517 upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale); 518 } else { 519 upperChar = Character.toUpperCaseEx(srcChar); 520 } 521 if (Character.isBmpCodePoint(upperChar)) { 522 StringUTF16.putChar(result, resultOffset++, upperChar); 523 } else { 524 if (upperChar == Character.ERROR) { 525 if (localeDependent) { 526 upperCharArray = 527 ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale); 528 } else { 529 upperCharArray = Character.toUpperCaseCharArray(srcChar); 530 } 531 } else { 532 upperCharArray = Character.toChars(upperChar); 533 } 534 /* Grow result if needed * 535 int mapLen = upperCharArray.length; 536 if (mapLen > 1) { 537 byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1); 538 System.arraycopy(result, 0, result2, 0, resultOffset << 1); 539 result = result2; 540 } 541 for (int x = 0; x < mapLen; ++x) { 542 StringUTF16.putChar(result, resultOffset++, upperCharArray[x]); 543 } 544 } 545 } 546 return StringUTF16.newString(result, 0, resultOffset); 547 } 548 */ 549 // END Android-removed: Remove unused code. 550 trim(byte[] value)551 public static String trim(byte[] value) { 552 int len = value.length; 553 int st = 0; 554 while ((st < len) && ((value[st] & 0xff) <= ' ')) { 555 st++; 556 } 557 while ((st < len) && ((value[len - 1] & 0xff) <= ' ')) { 558 len--; 559 } 560 return ((st > 0) || (len < value.length)) ? 561 newString(value, st, len - st) : null; 562 } 563 indexOfNonWhitespace(byte[] value)564 public static int indexOfNonWhitespace(byte[] value) { 565 int length = value.length; 566 int left = 0; 567 while (left < length) { 568 char ch = (char)(value[left] & 0xff); 569 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) { 570 break; 571 } 572 left++; 573 } 574 return left; 575 } 576 lastIndexOfNonWhitespace(byte[] value)577 public static int lastIndexOfNonWhitespace(byte[] value) { 578 int length = value.length; 579 int right = length; 580 while (0 < right) { 581 char ch = (char)(value[right - 1] & 0xff); 582 if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) { 583 break; 584 } 585 right--; 586 } 587 return right; 588 } 589 strip(byte[] value)590 public static String strip(byte[] value) { 591 int left = indexOfNonWhitespace(value); 592 if (left == value.length) { 593 return ""; 594 } 595 int right = lastIndexOfNonWhitespace(value); 596 return ((left > 0) || (right < value.length)) ? newString(value, left, right - left) : null; 597 } 598 stripLeading(byte[] value)599 public static String stripLeading(byte[] value) { 600 int left = indexOfNonWhitespace(value); 601 if (left == value.length) { 602 return ""; 603 } 604 return (left != 0) ? newString(value, left, value.length - left) : null; 605 } 606 stripTrailing(byte[] value)607 public static String stripTrailing(byte[] value) { 608 int right = lastIndexOfNonWhitespace(value); 609 if (right == 0) { 610 return ""; 611 } 612 return (right != value.length) ? newString(value, 0, right) : null; 613 } 614 615 private final static class LinesSpliterator implements Spliterator<String> { 616 private byte[] value; 617 private int index; // current index, modified on advance/split 618 private final int fence; // one past last index 619 LinesSpliterator(byte[] value)620 LinesSpliterator(byte[] value) { 621 this(value, 0, value.length); 622 } 623 LinesSpliterator(byte[] value, int start, int length)624 LinesSpliterator(byte[] value, int start, int length) { 625 this.value = value; 626 this.index = start; 627 this.fence = start + length; 628 } 629 indexOfLineSeparator(int start)630 private int indexOfLineSeparator(int start) { 631 for (int current = start; current < fence; current++) { 632 byte ch = value[current]; 633 if (ch == '\n' || ch == '\r') { 634 return current; 635 } 636 } 637 return fence; 638 } 639 skipLineSeparator(int start)640 private int skipLineSeparator(int start) { 641 if (start < fence) { 642 if (value[start] == '\r') { 643 int next = start + 1; 644 if (next < fence && value[next] == '\n') { 645 return next + 1; 646 } 647 } 648 return start + 1; 649 } 650 return fence; 651 } 652 next()653 private String next() { 654 int start = index; 655 int end = indexOfLineSeparator(start); 656 index = skipLineSeparator(end); 657 return newString(value, start, end - start); 658 } 659 660 @Override tryAdvance(Consumer<? super String> action)661 public boolean tryAdvance(Consumer<? super String> action) { 662 if (action == null) { 663 throw new NullPointerException("tryAdvance action missing"); 664 } 665 if (index != fence) { 666 action.accept(next()); 667 return true; 668 } 669 return false; 670 } 671 672 @Override forEachRemaining(Consumer<? super String> action)673 public void forEachRemaining(Consumer<? super String> action) { 674 if (action == null) { 675 throw new NullPointerException("forEachRemaining action missing"); 676 } 677 while (index != fence) { 678 action.accept(next()); 679 } 680 } 681 682 @Override trySplit()683 public Spliterator<String> trySplit() { 684 int half = (fence + index) >>> 1; 685 int mid = skipLineSeparator(indexOfLineSeparator(half)); 686 if (mid < fence) { 687 int start = index; 688 index = mid; 689 return new LinesSpliterator(value, start, mid - start); 690 } 691 return null; 692 } 693 694 @Override estimateSize()695 public long estimateSize() { 696 return fence - index + 1; 697 } 698 699 @Override characteristics()700 public int characteristics() { 701 return Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL; 702 } 703 } 704 lines(byte[] value)705 static Stream<String> lines(byte[] value) { 706 return StreamSupport.stream(new LinesSpliterator(value), false); 707 } 708 putChar(byte[] val, int index, int c)709 public static void putChar(byte[] val, int index, int c) { 710 //assert (canEncode(c)); 711 val[index] = (byte)(c); 712 } 713 getChar(byte[] val, int index)714 public static char getChar(byte[] val, int index) { 715 return (char)(val[index] & 0xff); 716 } 717 toBytes(int[] val, int off, int len)718 public static byte[] toBytes(int[] val, int off, int len) { 719 byte[] ret = new byte[len]; 720 for (int i = 0; i < len; i++) { 721 int cp = val[off++]; 722 if (!canEncode(cp)) { 723 return null; 724 } 725 ret[i] = (byte)cp; 726 } 727 return ret; 728 } 729 toBytes(char c)730 public static byte[] toBytes(char c) { 731 return new byte[] { (byte)c }; 732 } 733 newString(byte[] val, int index, int len)734 public static String newString(byte[] val, int index, int len) { 735 // Android-changed: Avoid byte[] allocation. 736 // return new String(Arrays.copyOfRange(val, index, index + len), 737 // LATIN1); 738 return new String(val, /*high=*/ 0, index, len); 739 } 740 fillNull(byte[] val, int index, int end)741 public static void fillNull(byte[] val, int index, int end) { 742 Arrays.fill(val, index, end, (byte)0); 743 } 744 745 // inflatedCopy byte[] -> char[] 746 @HotSpotIntrinsicCandidate inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len)747 public static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) { 748 for (int i = 0; i < len; i++) { 749 dst[dstOff++] = (char)(src[srcOff++] & 0xff); 750 } 751 } 752 753 // inflatedCopy byte[] -> byte[] 754 @HotSpotIntrinsicCandidate inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len)755 public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { 756 StringUTF16.inflate(src, srcOff, dst, dstOff, len); 757 } 758 759 static class CharsSpliterator implements Spliterator.OfInt { 760 private final byte[] array; 761 private int index; // current index, modified on advance/split 762 private final int fence; // one past last index 763 private final int cs; 764 CharsSpliterator(byte[] array, int acs)765 CharsSpliterator(byte[] array, int acs) { 766 this(array, 0, array.length, acs); 767 } 768 CharsSpliterator(byte[] array, int origin, int fence, int acs)769 CharsSpliterator(byte[] array, int origin, int fence, int acs) { 770 this.array = array; 771 this.index = origin; 772 this.fence = fence; 773 this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED 774 | Spliterator.SUBSIZED; 775 } 776 777 @Override trySplit()778 public OfInt trySplit() { 779 int lo = index, mid = (lo + fence) >>> 1; 780 return (lo >= mid) 781 ? null 782 : new CharsSpliterator(array, lo, index = mid, cs); 783 } 784 785 @Override forEachRemaining(IntConsumer action)786 public void forEachRemaining(IntConsumer action) { 787 byte[] a; int i, hi; // hoist accesses and checks from loop 788 if (action == null) 789 throw new NullPointerException(); 790 if ((a = array).length >= (hi = fence) && 791 (i = index) >= 0 && i < (index = hi)) { 792 do { action.accept(a[i] & 0xff); } while (++i < hi); 793 } 794 } 795 796 @Override tryAdvance(IntConsumer action)797 public boolean tryAdvance(IntConsumer action) { 798 if (action == null) 799 throw new NullPointerException(); 800 if (index >= 0 && index < fence) { 801 action.accept(array[index++] & 0xff); 802 return true; 803 } 804 return false; 805 } 806 807 @Override estimateSize()808 public long estimateSize() { return (long)(fence - index); } 809 810 @Override characteristics()811 public int characteristics() { 812 return cs; 813 } 814 } 815 } 816