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.util.Arrays; 27 import java.util.Comparator; 28 import libcore.util.CharsetUtils; 29 import libcore.util.EmptyArray; 30 31 /** 32 * Class used to generate strings instead of calling String.<init>. 33 * 34 * @hide 35 */ 36 public final class StringFactory { 37 38 // TODO: Remove once native methods are in place. 39 private static final char REPLACEMENT_CHAR = (char) 0xfffd; 40 newEmptyString()41 public static String newEmptyString() { 42 return newStringFromChars(EmptyArray.CHAR, 0, 0); 43 } 44 newStringFromBytes(byte[] data)45 public static String newStringFromBytes(byte[] data) { 46 return newStringFromBytes(data, 0, data.length); 47 } 48 newStringFromBytes(byte[] data, int high)49 public static String newStringFromBytes(byte[] data, int high) { 50 return newStringFromBytes(data, high, 0, data.length); 51 } 52 newStringFromBytes(byte[] data, int offset, int byteCount)53 public static String newStringFromBytes(byte[] data, int offset, int byteCount) { 54 return newStringFromBytes(data, offset, byteCount, Charset.defaultCharset()); 55 } 56 57 @FastNative newStringFromBytes(byte[] data, int high, int offset, int byteCount)58 public static native String newStringFromBytes(byte[] data, int high, int offset, int byteCount); 59 newStringFromBytes(byte[] data, int offset, int byteCount, String charsetName)60 public static String newStringFromBytes(byte[] data, int offset, int byteCount, String charsetName) throws UnsupportedEncodingException { 61 return newStringFromBytes(data, offset, byteCount, Charset.forNameUEE(charsetName)); 62 } 63 newStringFromBytes(byte[] data, String charsetName)64 public static String newStringFromBytes(byte[] data, String charsetName) throws UnsupportedEncodingException { 65 return newStringFromBytes(data, 0, data.length, Charset.forNameUEE(charsetName)); 66 } 67 68 // TODO: Implement this method natively. newStringFromBytes(byte[] data, int offset, int byteCount, Charset charset)69 public static String newStringFromBytes(byte[] data, int offset, int byteCount, Charset charset) { 70 if ((offset | byteCount) < 0 || byteCount > data.length - offset) { 71 throw new StringIndexOutOfBoundsException(data.length, offset, byteCount); 72 } 73 74 char[] value; 75 int length; 76 77 // We inline UTF-8, ISO-8859-1, and US-ASCII decoders for speed. 78 String canonicalCharsetName = charset.name(); 79 if (canonicalCharsetName.equals("UTF-8")) { 80 return newStringFromUtf8Bytes(data, offset, byteCount); 81 } else if (canonicalCharsetName.equals("ISO-8859-1")) { 82 value = new char[byteCount]; 83 length = byteCount; 84 CharsetUtils.isoLatin1BytesToChars(data, offset, byteCount, value); 85 } else if (canonicalCharsetName.equals("US-ASCII")) { 86 value = new char[byteCount]; 87 length = byteCount; 88 CharsetUtils.asciiBytesToChars(data, offset, byteCount, value); 89 } else { 90 CharBuffer cb = charset.decode(ByteBuffer.wrap(data, offset, byteCount)); 91 length = cb.length(); 92 // The call to newStringFromChars below will copy length bytes out of value, so it does 93 // not matter that cb.array().length may be > cb.length() or that a Charset could keep a 94 // reference to the CharBuffer it returns and later mutate it. 95 value = cb.array(); 96 } 97 return newStringFromChars(value, 0, length); 98 } 99 newStringFromBytes(byte[] data, Charset charset)100 public static String newStringFromBytes(byte[] data, Charset charset) { 101 return newStringFromBytes(data, 0, data.length, charset); 102 } 103 newStringFromChars(char[] data)104 public static String newStringFromChars(char[] data) { 105 return newStringFromChars(data, 0, data.length); 106 } 107 newStringFromChars(char[] data, int offset, int charCount)108 public static String newStringFromChars(char[] data, int offset, int charCount) { 109 if ((offset | charCount) < 0 || charCount > data.length - offset) { 110 throw new StringIndexOutOfBoundsException(data.length, offset, charCount); 111 } 112 return newStringFromChars(offset, charCount, data); 113 } 114 115 // The char array passed as {@code java_data} must not be a null reference. 116 @FastNative newStringFromChars(int offset, int charCount, char[] data)117 static native String newStringFromChars(int offset, int charCount, char[] data); 118 119 @FastNative newStringFromString(String toCopy)120 public static native String newStringFromString(String toCopy); 121 122 @FastNative newStringFromUtf8Bytes(byte[] data, int offset, int byteCount)123 public static native String newStringFromUtf8Bytes(byte[] data, int offset, int byteCount); 124 newStringFromStringBuffer(StringBuffer stringBuffer)125 public static String newStringFromStringBuffer(StringBuffer stringBuffer) { 126 synchronized (stringBuffer) { 127 return newStringFromChars(stringBuffer.getValue(), 0, stringBuffer.length()); 128 } 129 } 130 131 // TODO: Implement this method natively. newStringFromCodePoints(int[] codePoints, int offset, int count)132 public static String newStringFromCodePoints(int[] codePoints, int offset, int count) { 133 if (codePoints == null) { 134 throw new NullPointerException("codePoints == null"); 135 } 136 if ((offset | count) < 0 || count > codePoints.length - offset) { 137 throw new StringIndexOutOfBoundsException(codePoints.length, offset, count); 138 } 139 char[] value = new char[count * 2]; 140 int end = offset + count; 141 int length = 0; 142 for (int i = offset; i < end; i++) { 143 length += Character.toChars(codePoints[i], value, length); 144 } 145 return newStringFromChars(value, 0, length); 146 } 147 newStringFromStringBuilder(StringBuilder stringBuilder)148 public static String newStringFromStringBuilder(StringBuilder stringBuilder) { 149 return newStringFromChars(stringBuilder.getValue(), 0, stringBuilder.length()); 150 } 151 } 152