1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.lang; 19 20 import dalvik.annotation.optimization.FastNative; 21 import java.io.Serializable; 22 import java.io.UnsupportedEncodingException; 23 import java.nio.ByteBuffer; 24 import java.nio.CharBuffer; 25 import java.nio.charset.Charset; 26 import java.nio.charset.StandardCharsets; 27 import java.util.Arrays; 28 import java.util.Comparator; 29 import libcore.util.CharsetUtils; 30 import libcore.util.EmptyArray; 31 32 /** 33 * Class used to generate strings instead of calling String.<init>. 34 * 35 * @hide 36 */ 37 public final class StringFactory { 38 newEmptyString()39 public static String newEmptyString() { 40 return newStringFromChars(EmptyArray.CHAR, 0, 0); 41 } 42 newStringFromBytes(byte[] data)43 public static String newStringFromBytes(byte[] data) { 44 return newStringFromBytes(data, 0, data.length); 45 } 46 newStringFromBytes(byte[] data, byte coder)47 public static String newStringFromBytes(byte[] data, byte coder) { 48 if (coder == String.LATIN1) { 49 return newStringFromBytes(data, /*high=*/ 0); 50 } else { 51 return newStringFromUtf16Bytes(data, 0, data.length >>> 1); 52 } 53 } 54 55 /** 56 * This method doesn't validate any UTF-16 sequence, but simply convert each byte pair 57 * into 2-byte char. To produce valid UTF-16 sequence, please use 58 * {@link StandardCharsets#UTF_16} instead. 59 */ 60 @FastNative newStringFromUtf16Bytes(byte[] data, int offset, int charCount)61 public static native String newStringFromUtf16Bytes(byte[] data, int offset, int charCount); 62 newStringFromBytes(byte[] data, int high)63 public static String newStringFromBytes(byte[] data, int high) { 64 return newStringFromBytes(data, high, 0, data.length); 65 } 66 newStringFromBytes(byte[] data, int offset, int byteCount)67 public static String newStringFromBytes(byte[] data, int offset, int byteCount) { 68 return newStringFromBytes(data, offset, byteCount, Charset.defaultCharset()); 69 } 70 71 @FastNative newStringFromBytes(byte[] data, int high, int offset, int byteCount)72 public static native String newStringFromBytes(byte[] data, int high, int offset, int byteCount); 73 newStringFromBytes(byte[] data, int offset, int byteCount, String charsetName)74 public static String newStringFromBytes(byte[] data, int offset, int byteCount, String charsetName) throws UnsupportedEncodingException { 75 return newStringFromBytes(data, offset, byteCount, Charset.forNameUEE(charsetName)); 76 } 77 newStringFromBytes(byte[] data, String charsetName)78 public static String newStringFromBytes(byte[] data, String charsetName) throws UnsupportedEncodingException { 79 return newStringFromBytes(data, 0, data.length, Charset.forNameUEE(charsetName)); 80 } 81 82 // TODO: Implement this method natively. newStringFromBytes(byte[] data, int offset, int byteCount, Charset charset)83 public static String newStringFromBytes(byte[] data, int offset, int byteCount, Charset charset) { 84 if ((offset | byteCount) < 0 || byteCount > data.length - offset) { 85 throw new StringIndexOutOfBoundsException(data.length, offset, byteCount); 86 } 87 88 char[] value; 89 int length; 90 91 // We inline UTF-8, ISO-8859-1, and US-ASCII decoders for speed. 92 String canonicalCharsetName = charset.name(); 93 if (canonicalCharsetName.equals("UTF-8")) { 94 return newStringFromUtf8Bytes(data, offset, byteCount); 95 } else if (canonicalCharsetName.equals("ISO-8859-1")) { 96 return newStringFromBytes(data, /*high=*/ 0, offset, byteCount); 97 } else if (canonicalCharsetName.equals("US-ASCII")) { 98 value = new char[byteCount]; 99 length = byteCount; 100 CharsetUtils.asciiBytesToChars(data, offset, byteCount, value); 101 } else { 102 CharBuffer cb = charset.decode(ByteBuffer.wrap(data, offset, byteCount)); 103 length = cb.length(); 104 // The call to newStringFromChars below will copy length bytes out of value, so it does 105 // not matter that cb.array().length may be > cb.length() or that a Charset could keep a 106 // reference to the CharBuffer it returns and later mutate it. 107 value = cb.array(); 108 } 109 return newStringFromChars(value, 0, length); 110 } 111 newStringFromBytes(byte[] data, Charset charset)112 public static String newStringFromBytes(byte[] data, Charset charset) { 113 return newStringFromBytes(data, 0, data.length, charset); 114 } 115 newStringFromChars(char[] data)116 public static String newStringFromChars(char[] data) { 117 return newStringFromChars(data, 0, data.length); 118 } 119 newStringFromChars(char[] data, int offset, int charCount)120 public static String newStringFromChars(char[] data, int offset, int charCount) { 121 if ((offset | charCount) < 0 || charCount > data.length - offset) { 122 throw new StringIndexOutOfBoundsException(data.length, offset, charCount); 123 } 124 return newStringFromChars(offset, charCount, data); 125 } 126 127 // The char array passed as {@code java_data} must not be a null reference. 128 @FastNative newStringFromChars(int offset, int charCount, char[] data)129 static native String newStringFromChars(int offset, int charCount, char[] data); 130 131 @FastNative newStringFromString(String toCopy)132 public static native String newStringFromString(String toCopy); 133 134 @FastNative newStringFromUtf8Bytes(byte[] data, int offset, int byteCount)135 public static native String newStringFromUtf8Bytes(byte[] data, int offset, int byteCount); 136 newStringFromStringBuffer(StringBuffer stringBuffer)137 public static String newStringFromStringBuffer(StringBuffer stringBuffer) { 138 synchronized (stringBuffer) { 139 byte[] value = stringBuffer.getValue(); 140 int length = stringBuffer.length(); 141 if (stringBuffer.isLatin1()) { 142 return newStringFromBytes(value, /*high=*/ 0, /*offset=*/ 0, length); 143 } else { 144 return newStringFromUtf16Bytes(value, 0, length); 145 } 146 } 147 } 148 149 // TODO: Implement this method natively. newStringFromCodePoints(int[] codePoints, int offset, int count)150 public static String newStringFromCodePoints(int[] codePoints, int offset, int count) { 151 if (codePoints == null) { 152 throw new NullPointerException("codePoints == null"); 153 } 154 if ((offset | count) < 0 || count > codePoints.length - offset) { 155 throw new StringIndexOutOfBoundsException(codePoints.length, offset, count); 156 } 157 char[] value = new char[count * 2]; 158 int end = offset + count; 159 int length = 0; 160 for (int i = offset; i < end; i++) { 161 length += Character.toChars(codePoints[i], value, length); 162 } 163 return newStringFromChars(value, 0, length); 164 } 165 newStringFromStringBuilder(StringBuilder stringBuilder)166 public static String newStringFromStringBuilder(StringBuilder stringBuilder) { 167 byte[] value = stringBuilder.getValue(); 168 int length = stringBuilder.length(); 169 if (stringBuilder.isLatin1()) { 170 return newStringFromBytes(value, /*high=*/ 0, /*offset=*/ 0, length); 171 } else { 172 return newStringFromUtf16Bytes(value, 0, length); 173 } 174 } 175 } 176