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