1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License. 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License. 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.rop.cst; 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Type; 20333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport com.android.dx.util.ByteArray; 21333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport com.android.dx.util.Hex; 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** 24333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Constants of type {@code CONSTANT_Utf8_info} or {@code CONSTANT_String_info}. 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 26333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonpublic final class CstString extends TypedConstant { 27333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 28333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * {@code non-null;} instance representing {@code ""}, that is, the 29333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * empty string 30333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 31333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public static final CstString EMPTY_STRING = new CstString(""); 32333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 33333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** {@code non-null;} the UTF-8 value as a string */ 34333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson private final String string; 35333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 36333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** {@code non-null;} the UTF-8 value as bytes */ 37333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson private final ByteArray bytes; 38333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 39333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 40333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Converts a string into its MUTF-8 form. MUTF-8 differs from normal UTF-8 41333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * in the handling of character '\0' and surrogate pairs. 42333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * 43333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @param string {@code non-null;} the string to convert 44333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return {@code non-null;} the UTF-8 bytes for it 45333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 46333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public static byte[] stringToUtf8Bytes(String string) { 47333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int len = string.length(); 48333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson byte[] bytes = new byte[len * 3]; // Avoid having to reallocate. 49333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int outAt = 0; 50333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 51333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson for (int i = 0; i < len; i++) { 52333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson char c = string.charAt(i); 53333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if ((c != 0) && (c < 0x80)) { 54333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson bytes[outAt] = (byte) c; 55333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson outAt++; 56333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } else if (c < 0x800) { 57333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson bytes[outAt] = (byte) (((c >> 6) & 0x1f) | 0xc0); 58333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson bytes[outAt + 1] = (byte) ((c & 0x3f) | 0x80); 59333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson outAt += 2; 60333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } else { 61333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson bytes[outAt] = (byte) (((c >> 12) & 0x0f) | 0xe0); 62333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson bytes[outAt + 1] = (byte) (((c >> 6) & 0x3f) | 0x80); 63333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson bytes[outAt + 2] = (byte) ((c & 0x3f) | 0x80); 64333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson outAt += 3; 65333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 66333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 67333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 68333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson byte[] result = new byte[outAt]; 69333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson System.arraycopy(bytes, 0, result, 0, outAt); 70333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return result; 71333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 74333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Converts an array of UTF-8 bytes into a string. 75de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 76333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @param bytes {@code non-null;} the bytes to convert 77333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return {@code non-null;} the converted string 78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 79333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public static String utf8BytesToString(ByteArray bytes) { 80333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int length = bytes.size(); 81333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson char[] chars = new char[length]; // This is sized to avoid a realloc. 82333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int outAt = 0; 83333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 84333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson for (int at = 0; length > 0; /*at*/) { 85333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int v0 = bytes.getUnsignedByte(at); 86333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson char out; 87333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson switch (v0 >> 4) { 88333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson case 0x00: case 0x01: case 0x02: case 0x03: 89333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson case 0x04: case 0x05: case 0x06: case 0x07: { 90333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson // 0XXXXXXX -- single-byte encoding 91333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson length--; 92333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if (v0 == 0) { 93333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson // A single zero byte is illegal. 94333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v0, at); 95333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 96333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson out = (char) v0; 97333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson at++; 98333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson break; 99333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 100333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson case 0x0c: case 0x0d: { 101333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson // 110XXXXX -- two-byte encoding 102333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson length -= 2; 103333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if (length < 0) { 104333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v0, at); 105333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 106333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int v1 = bytes.getUnsignedByte(at + 1); 107333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if ((v1 & 0xc0) != 0x80) { 108333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v1, at + 1); 109333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 110333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f); 111333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if ((value != 0) && (value < 0x80)) { 112333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /* 113333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * This should have been represented with 114333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * one-byte encoding. 115333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 116333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v1, at + 1); 117333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 118333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson out = (char) value; 119333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson at += 2; 120333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson break; 121333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 122333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson case 0x0e: { 123333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson // 1110XXXX -- three-byte encoding 124333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson length -= 3; 125333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if (length < 0) { 126333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v0, at); 127333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 128333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int v1 = bytes.getUnsignedByte(at + 1); 129333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if ((v1 & 0xc0) != 0x80) { 130333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v1, at + 1); 131333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 132333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int v2 = bytes.getUnsignedByte(at + 2); 133333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if ((v1 & 0xc0) != 0x80) { 134333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v2, at + 2); 135333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 136333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) | 137333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson (v2 & 0x3f); 138333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if (value < 0x800) { 139333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /* 140333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * This should have been represented with one- or 141333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * two-byte encoding. 142333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 143333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v2, at + 2); 144333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 145333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson out = (char) value; 146333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson at += 3; 147333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson break; 148333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 149333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson default: { 150333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson // 10XXXXXX, 1111XXXX -- illegal 151333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return throwBadUtf8(v0, at); 152333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 153333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 154333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson chars[outAt] = out; 155333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson outAt++; 156333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 157333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 158333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return new String(chars, 0, outAt); 159333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 160333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 161333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 162333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Helper for {@link #utf8BytesToString}, which throws the right 163333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * exception for a bogus utf-8 byte. 164333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * 165333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @param value the byte value 166333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @param offset the file offset 167333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return never 168333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @throws IllegalArgumentException always thrown 169333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 170333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson private static String throwBadUtf8(int value, int offset) { 171333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson throw new IllegalArgumentException("bad utf-8 byte " + Hex.u1(value) + 172333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson " at offset " + Hex.u4(offset)); 173333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 174333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 175333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 176333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Constructs an instance from a {@code String}. 177333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * 178333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @param string {@code non-null;} the UTF-8 value as a string 179333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 180333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public CstString(String string) { 181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (string == null) { 182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new NullPointerException("string == null"); 183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 185333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson this.string = string.intern(); 186333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson this.bytes = new ByteArray(stringToUtf8Bytes(string)); 187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 190333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Constructs an instance from some UTF-8 bytes. 191de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 192333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @param bytes {@code non-null;} array of the UTF-8 bytes 193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 194333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public CstString(ByteArray bytes) { 195333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if (bytes == null) { 196333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson throw new NullPointerException("bytes == null"); 197333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 198333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 199333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson this.bytes = bytes; 200333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson this.string = utf8BytesToString(bytes).intern(); 201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public boolean equals(Object other) { 206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!(other instanceof CstString)) { 207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return string.equals(((CstString) other).string); 211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public int hashCode() { 216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return string.hashCode(); 217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project protected int compareTo0(Constant other) { 222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return string.compareTo(((CstString) other).string); 223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public String toString() { 228333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return "string{\"" + toHuman() + "\"}"; 229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public String typeName() { 234333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return "utf8"; 235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public boolean isCategory2() { 240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public String toHuman() { 245333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int len = string.length(); 246333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson StringBuilder sb = new StringBuilder(len * 3 / 2); 247333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 248333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson for (int i = 0; i < len; i++) { 249333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson char c = string.charAt(i); 250333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if ((c >= ' ') && (c < 0x7f)) { 251333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if ((c == '\'') || (c == '\"') || (c == '\\')) { 252333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append('\\'); 253333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 254333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append(c); 255333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } else if (c <= 0x7f) { 256333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson switch (c) { 257333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson case '\n': sb.append("\\n"); break; 258333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson case '\r': sb.append("\\r"); break; 259333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson case '\t': sb.append("\\t"); break; 260333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson default: { 261333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /* 262333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Represent the character as an octal escape. 263333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * If the next character is a valid octal 264333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * digit, disambiguate by using the 265333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * three-digit form. 266333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 267333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson char nextChar = 268333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson (i < (len - 1)) ? string.charAt(i + 1) : 0; 269333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson boolean displayZero = 270333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson (nextChar >= '0') && (nextChar <= '7'); 271333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append('\\'); 272333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson for (int shift = 6; shift >= 0; shift -= 3) { 273333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson char outChar = (char) (((c >> shift) & 7) + '0'); 274333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if ((outChar != '0') || displayZero) { 275333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append(outChar); 276333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson displayZero = true; 277333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 278333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 279333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if (! displayZero) { 280333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson // Ironic edge case: The original value was 0. 281333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append('0'); 282333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 283333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson break; 284333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 285333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 286333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } else { 287333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append("\\u"); 288333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append(Character.forDigit(c >> 12, 16)); 289333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append(Character.forDigit((c >> 8) & 0x0f, 16)); 290333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append(Character.forDigit((c >> 4) & 0x0f, 16)); 291333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson sb.append(Character.forDigit(c & 0x0f, 16)); 292333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 293333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 294333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 295333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return sb.toString(); 296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 299333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Gets the value as a human-oriented string, surrounded by double 300333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * quotes. 301de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 302333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return {@code non-null;} the quoted string 303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 304333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public String toQuoted() { 305333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return '\"' + toHuman() + '\"'; 306333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 307333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 308333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 309333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Gets the value as a human-oriented string, surrounded by double 310333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * quotes, but ellipsizes the result if it is longer than the given 311333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * maximum length 312333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * 313333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @param maxLength {@code >= 5;} the maximum length of the string to return 314333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return {@code non-null;} the quoted string 315333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 316333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public String toQuoted(int maxLength) { 317333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson String string = toHuman(); 318333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson int length = string.length(); 319333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson String ellipses; 320333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 321333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson if (length <= (maxLength - 2)) { 322333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson ellipses = ""; 323333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } else { 324333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson string = string.substring(0, maxLength - 5); 325333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson ellipses = "..."; 326333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 327333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 328333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return '\"' + string + ellipses + '\"'; 329333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 330333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 331333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 332333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Gets the UTF-8 value as a string. 333333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * The returned string is always already interned. 334333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * 335333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return {@code non-null;} the UTF-8 value as a string 336333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 337333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public String getString() { 338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return string; 339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 340333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 341333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 342333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Gets the UTF-8 value as UTF-8 encoded bytes. 343333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * 344333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return {@code non-null;} an array of the UTF-8 bytes 345333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 346333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public ByteArray getBytes() { 347333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return bytes; 348333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 349333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 350333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 351333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Gets the size of this instance as UTF-8 code points. That is, 352333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * get the number of bytes in the UTF-8 encoding of this instance. 353333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * 354333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return {@code >= 0;} the UTF-8 size 355333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 356333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public int getUtf8Size() { 357333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return bytes.size(); 358333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 359333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 360333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson /** 361333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Gets the size of this instance as UTF-16 code points. That is, 362333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * get the number of 16-bit chars in the UTF-16 encoding of this 363333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * instance. This is the same as the {@code length} of the 364333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * Java {@code String} representation of this instance. 365333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * 366333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson * @return {@code >= 0;} the UTF-16 size 367333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson */ 368333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public int getUtf16Size() { 369333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return string.length(); 370333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 371333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson 372333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson public Type getType() { 373333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson return Type.STRING; 374333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson } 375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 376