• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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