IccUtils.java revision f3e659e2865fe52af5a87efb52299b81005aeb17
1f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold/* 2f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Copyright (C) 2006 The Android Open Source Project 3f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 4f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Licensed under the Apache License, Version 2.0 (the "License"); 5f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * you may not use this file except in compliance with the License. 6f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * You may obtain a copy of the License at 7f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 8f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * http://www.apache.org/licenses/LICENSE-2.0 9f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 10f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Unless required by applicable law or agreed to in writing, software 11f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * distributed under the License is distributed on an "AS IS" BASIS, 12f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * See the License for the specific language governing permissions and 14f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * limitations under the License. 15f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 16f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 17f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldpackage com.android.internal.telephony.uicc; 18f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 19f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldimport android.content.res.Resources; 20f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldimport android.content.res.Resources.NotFoundException; 21f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldimport android.graphics.Bitmap; 22f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldimport android.graphics.Color; 23f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldimport android.telephony.Rlog; 24f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 25f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldimport com.android.internal.telephony.GsmAlphabet; 26f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 27f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldimport java.io.UnsupportedEncodingException; 28f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 29f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold/** 30f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Various methods, useful for dealing with SIM data. 31f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 32f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Haroldpublic class IccUtils { 33f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold static final String LOG_TAG="IccUtils"; 34f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 35f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 36f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Many fields in GSM SIM's are stored as nibble-swizzled BCD 37f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 38f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Assumes left-justified field that may be padded right with 0xf 39f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * values. 40f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 41f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Stops on invalid BCD value, returning string so far 42f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 43f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 44f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bcdToString(byte[] data, int offset, int length) { 45f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(length*2); 46f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 47f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i = offset ; i < offset + length ; i++) { 48f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int v; 49f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 50f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = data[i] & 0xf; 51f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v > 9) break; 52f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char)('0' + v)); 53f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 54f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = (data[i] >> 4) & 0xf; 55f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // Some PLMNs have 'f' as high nibble, ignore it 56f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v == 0xf) continue; 57f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v > 9) break; 58f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char)('0' + v)); 59f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 60f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 61f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 62f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 63f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 64f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 65f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3 66f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Returns a concatenated string of MCC+MNC, stripping 67f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * a trailing character for a 2-digit MNC 68f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 69f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String bcdPlmnToString(byte[] data, int offset) { 70f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (offset + 3 > data.length) { 71f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return null; 72f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 73f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold byte[] trans = new byte[3]; 74f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold trans[0] = (byte) ((data[0 + offset] << 4) | ((data[0 + offset] >> 4) & 0xF)); 75f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold trans[1] = (byte) ((data[1 + offset] << 4) | (data[2 + offset] & 0xF)); 76f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold trans[2] = (byte) ((data[2 + offset] & 0xF0) | ((data[1 + offset] >> 4) & 0xF)); 77f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold String ret = bytesToHexString(trans); 78f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 79f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // For a 2-digit MNC we trim the trailing 'f' 80f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (ret.endsWith("f")) { 81f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = ret.substring(0, ret.length() - 1); 82f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 83f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 84f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 85f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 86f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 87f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH 88f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 89f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 90f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bchToString(byte[] data, int offset, int length) { 91f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(length*2); 92f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 93f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i = offset ; i < offset + length ; i++) { 94f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int v; 95f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 96f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = data[i] & 0xf; 97f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append("0123456789abcdef".charAt(v)); 98f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 99f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = (data[i] >> 4) & 0xf; 100f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append("0123456789abcdef".charAt(v)); 101f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 102f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 103f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 104f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 105f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 106f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 107f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Decode cdma byte into String. 108f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 109f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 110f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold cdmaBcdToString(byte[] data, int offset, int length) { 111f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(length); 112f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 113f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int count = 0; 114f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i = offset; count < length; i++) { 115f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int v; 116f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = data[i] & 0xf; 117f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v > 9) v = 0; 118f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char)('0' + v)); 119f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 120f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (++count == length) break; 121f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 122f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = (data[i] >> 4) & 0xf; 123f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v > 9) v = 0; 124f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char)('0' + v)); 125f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ++count; 126f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 127f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 128f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 129f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 130f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 131f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Decodes a GSM-style BCD byte, returning an int ranging from 0-99. 132f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 133f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * In GSM land, the least significant BCD digit is stored in the most 134f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * significant nibble. 135f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 136f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Out-of-range digits are treated as 0 for the sake of the time stamp, 137f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * because of this: 138f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 139f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * TS 23.040 section 9.2.3.11 140f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * "if the MS receives a non-integer value in the SCTS, it shall 141f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * assume the digit is set to 0 but shall store the entire field 142f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * exactly as received" 143f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 144f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static int 145f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold gsmBcdByteToInt(byte b) { 146f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int ret = 0; 147f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 148f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // treat out-of-range BCD values as 0 149f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((b & 0xf0) <= 0x90) { 150f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = (b >> 4) & 0xf; 151f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 152f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 153f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((b & 0x0f) <= 0x09) { 154f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret += (b & 0xf) * 10; 155f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 156f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 157f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 158f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 159f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 160f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 161f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Decodes a CDMA style BCD byte like {@link #gsmBcdByteToInt}, but 162f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * opposite nibble format. The least significant BCD digit 163f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * is in the least significant nibble and the most significant 164f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * is in the most significant nibble. 165f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 166f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static int 167f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold cdmaBcdByteToInt(byte b) { 168f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int ret = 0; 169f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 170f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // treat out-of-range BCD values as 0 171f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((b & 0xf0) <= 0x90) { 172f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = ((b >> 4) & 0xf) * 10; 173f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 174f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 175f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((b & 0x0f) <= 0x09) { 176f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret += (b & 0xf); 177f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 178f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 179f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 180f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 181f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 182f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 183f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Decodes a string field that's formatted like the EF[ADN] alpha 184f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * identifier 185f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 186f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * From TS 51.011 10.5.1: 187f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Coding: 188f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * this alpha tagging shall use either 189f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * - the SMS default 7 bit coded alphabet as defined in 190f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * TS 23.038 [12] with bit 8 set to 0. The alpha identifier 191f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * shall be left justified. Unused bytes shall be set to 'FF'; or 192f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * - one of the UCS2 coded options as defined in annex B. 193f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 194f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Annex B from TS 11.11 V8.13.0: 195f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 1) If the first octet in the alpha string is '80', then the 196f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * remaining octets are 16 bit UCS2 characters ... 197f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 2) if the first octet in the alpha string is '81', then the 198f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * second octet contains a value indicating the number of 199f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * characters in the string, and the third octet contains an 200f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 8 bit number which defines bits 15 to 8 of a 16 bit 201f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * base pointer, where bit 16 is set to zero and bits 7 to 1 202f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * are also set to zero. These sixteen bits constitute a 203f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * base pointer to a "half page" in the UCS2 code space, to be 204f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * used with some or all of the remaining octets in the string. 205f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * The fourth and subsequent octets contain codings as follows: 206f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * If bit 8 of the octet is set to zero, the remaining 7 bits 207f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * of the octet contain a GSM Default Alphabet character, 208f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * whereas if bit 8 of the octet is set to one, then the 209f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * remaining seven bits are an offset value added to the 210f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 16 bit base pointer defined earlier... 211f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 3) If the first octet of the alpha string is set to '82', then 212f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * the second octet contains a value indicating the number of 213f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * characters in the string, and the third and fourth octets 214f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * contain a 16 bit number which defines the complete 16 bit 215f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * base pointer to a "half page" in the UCS2 code space... 216f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 217f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 218f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold adnStringFieldToString(byte[] data, int offset, int length) { 219f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (length == 0) { 220f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ""; 221f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 222f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (length >= 1) { 223f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (data[offset] == (byte) 0x80) { 224f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int ucslen = (length - 1) / 2; 225f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold String ret = null; 226f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 227f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold try { 228f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = new String(data, offset + 1, ucslen * 2, "utf-16be"); 229f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } catch (UnsupportedEncodingException ex) { 230f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException", 231f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ex); 232f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 233f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 234f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (ret != null) { 235f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // trim off trailing FFFF characters 236f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 237f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ucslen = ret.length(); 238f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (ucslen > 0 && ret.charAt(ucslen - 1) == '\uFFFF') 239f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ucslen--; 240f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 241f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.substring(0, ucslen); 242f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 243f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 244f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 245f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 246f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold boolean isucs2 = false; 247f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold char base = '\0'; 248f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int len = 0; 249f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 250f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (length >= 3 && data[offset] == (byte) 0x81) { 251f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len = data[offset + 1] & 0xFF; 252f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (len > length - 3) 253f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len = length - 3; 254f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 255f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold base = (char) ((data[offset + 2] & 0xFF) << 7); 256f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset += 3; 257f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold isucs2 = true; 258f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } else if (length >= 4 && data[offset] == (byte) 0x82) { 259f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len = data[offset + 1] & 0xFF; 260f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (len > length - 4) 261f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len = length - 4; 262f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 263f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold base = (char) (((data[offset + 2] & 0xFF) << 8) | 264f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold (data[offset + 3] & 0xFF)); 265f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset += 4; 266f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold isucs2 = true; 267f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 268f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 269f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (isucs2) { 270f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(); 271f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 272f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (len > 0) { 273f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // UCS2 subset case 274f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 275f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (data[offset] < 0) { 276f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char) (base + (data[offset] & 0x7F))); 277f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset++; 278f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len--; 279f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 280f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 281f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // GSM character set case 282f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 283f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int count = 0; 284f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (count < len && data[offset + count] >= 0) 285f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold count++; 286f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 287f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append(GsmAlphabet.gsm8BitUnpackedToString(data, 288f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset, count)); 289f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 290f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset += count; 291f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len -= count; 292f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 293f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 294f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 295f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 296f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 297f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Resources resource = Resources.getSystem(); 298f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold String defaultCharset = ""; 299f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold try { 300f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold defaultCharset = 301f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold resource.getString(com.android.internal.R.string.gsm_alphabet_default_charset); 302f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } catch (NotFoundException e) { 303f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // Ignore Exception and defaultCharset is set to a empty string. 304f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 305f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim()); 306f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 307f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 308f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold static int 309f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold hexCharToInt(char c) { 310f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (c >= '0' && c <= '9') return (c - '0'); 311f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (c >= 'A' && c <= 'F') return (c - 'A' + 10); 312f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (c >= 'a' && c <= 'f') return (c - 'a' + 10); 313f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 314f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold throw new RuntimeException ("invalid hex char '" + c + "'"); 315f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 316f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 317f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 318f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Converts a hex String to a byte array. 319f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 320f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param s A string of hexadecimal characters, must be an even number of 321f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * chars long 322f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 323f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @return byte array representation 324f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 325f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @throws RuntimeException on invalid format 326f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 327f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static byte[] 328f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold hexStringToBytes(String s) { 329f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold byte[] ret; 330f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 331f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (s == null) return null; 332f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 333f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int sz = s.length(); 334f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 335f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = new byte[sz/2]; 336f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 337f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i=0 ; i <sz ; i+=2) { 338f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) 339f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | hexCharToInt(s.charAt(i+1))); 340f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 341f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 342f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 343f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 344f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 345f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 346f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 347f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Converts a byte array into a String of hexadecimal characters. 348f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 349f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param bytes an array of bytes 350f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 351f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @return hex string representation of bytes array 352f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 353f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 354f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bytesToHexString(byte[] bytes) { 355f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (bytes == null) return null; 356f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 357f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(2*bytes.length); 358f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 359f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i = 0 ; i < bytes.length ; i++) { 360f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int b; 361f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 362f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold b = 0x0f & (bytes[i] >> 4); 363f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 364f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append("0123456789abcdef".charAt(b)); 365f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 366f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold b = 0x0f & bytes[i]; 367f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 368f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append("0123456789abcdef".charAt(b)); 369f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 370f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 371f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 372f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 373f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 374f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 375f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 376f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Convert a TS 24.008 Section 10.5.3.5a Network Name field to a string 377f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * "offset" points to "octet 3", the coding scheme byte 378f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * empty string returned on decode error 379f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 380f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 381f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold networkNameToString(byte[] data, int offset, int length) { 382f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold String ret; 383f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 384f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((data[offset] & 0x80) != 0x80 || length < 1) { 385f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ""; 386f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 387f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 388f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold switch ((data[offset] >>> 4) & 0x7) { 389f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 0: 390f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // SMS character set 391f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int countSeptets; 392f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int unusedBits = data[offset] & 7; 393f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold countSeptets = (((length - 1) * 8) - unusedBits) / 7 ; 394f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets); 395f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 396f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 1: 397f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // UCS2 398f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold try { 399f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = new String(data, 400f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset + 1, length - 1, "utf-16"); 401f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } catch (UnsupportedEncodingException ex) { 402f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = ""; 403f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG,"implausible UnsupportedEncodingException", ex); 404f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 405f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 406f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 407f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // unsupported encoding 408f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold default: 409f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = ""; 410f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 411f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 412f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 413f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // "Add CI" 414f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // "The MS should add the letters for the Country's Initials and 415f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // a separator (e.g. a space) to the text string" 416f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 417f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((data[offset] & 0x40) != 0) { 418f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // FIXME(mkf) add country initials here 419f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 420f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 421f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 422f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 423f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 424f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 425f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 426f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Convert a TS 131.102 image instance of code scheme '11' into Bitmap 427f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param data The raw data 428f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param length The length of image body 429f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @return The bitmap 430f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 431f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static Bitmap parseToBnW(byte[] data, int length){ 432f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int valueIndex = 0; 433f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int width = data[valueIndex++] & 0xFF; 434f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int height = data[valueIndex++] & 0xFF; 435f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int numOfPixels = width*height; 436f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 437f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] pixels = new int[numOfPixels]; 438f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 439f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int pixelIndex = 0; 440f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int bitIndex = 7; 441f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold byte currentByte = 0x00; 442f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (pixelIndex < numOfPixels) { 443f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // reassign data and index for every byte (8 bits). 444f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (pixelIndex % 8 == 0) { 445f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold currentByte = data[valueIndex++]; 446f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bitIndex = 7; 447f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 448f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold pixels[pixelIndex++] = bitToRGB((currentByte >> bitIndex-- ) & 0x01); 449f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 450f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 451f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (pixelIndex != numOfPixels) { 452f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG, "parse end and size error"); 453f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 454f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); 455f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 456f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 457f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold private static int bitToRGB(int bit){ 458f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if(bit == 1){ 459f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return Color.WHITE; 460f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } else { 461f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return Color.BLACK; 462f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 463f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 464f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 465f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 466f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * a TS 131.102 image instance of code scheme '11' into color Bitmap 467f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 468f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param data The raw data 469f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param length the length of image body 470f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param transparency with or without transparency 471f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @return The color bitmap 472f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 473f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static Bitmap parseToRGB(byte[] data, int length, 474f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold boolean transparency) { 475f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int valueIndex = 0; 476f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int width = data[valueIndex++] & 0xFF; 477f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int height = data[valueIndex++] & 0xFF; 478f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int bits = data[valueIndex++] & 0xFF; 479f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int colorNumber = data[valueIndex++] & 0xFF; 480f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int clutOffset = ((data[valueIndex++] & 0xFF) << 8) 481f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | (data[valueIndex++] & 0xFF); 482f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 483f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber); 484f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (true == transparency) { 485f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold colorIndexArray[colorNumber - 1] = Color.TRANSPARENT; 486f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 487f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 488f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] resultArray = null; 489f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (0 == (8 % bits)) { 490f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold resultArray = mapTo2OrderBitColor(data, valueIndex, 491f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold (width * height), colorIndexArray, bits); 492f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } else { 493f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold resultArray = mapToNon2OrderBitColor(data, valueIndex, 494f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold (width * height), colorIndexArray, bits); 495f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 496f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 497f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return Bitmap.createBitmap(resultArray, width, height, 498f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Bitmap.Config.RGB_565); 499f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 500f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 501f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold private static int[] mapTo2OrderBitColor(byte[] data, int valueIndex, 502f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int length, int[] colorArray, int bits) { 503f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (0 != (8 % bits)) { 504f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG, "not event number of color"); 505f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return mapToNon2OrderBitColor(data, valueIndex, length, colorArray, 506f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bits); 507f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 508f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 509f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int mask = 0x01; 510f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold switch (bits) { 511f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 1: 512f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold mask = 0x01; 513f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 514f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 2: 515f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold mask = 0x03; 516f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 517f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 4: 518f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold mask = 0x0F; 519f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 520f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 8: 521f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold mask = 0xFF; 522f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 523f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 524f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 525f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] resultArray = new int[length]; 526f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int resultIndex = 0; 527f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int run = 8 / bits; 528f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (resultIndex < length) { 529f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold byte tempByte = data[valueIndex++]; 530f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int runIndex = 0; runIndex < run; ++runIndex) { 531f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int offset = run - runIndex - 1; 532f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold resultArray[resultIndex++] = colorArray[(tempByte >> (offset * bits)) 533f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold & mask]; 534f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 535f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 536f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return resultArray; 537f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 538f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 539f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold private static int[] mapToNon2OrderBitColor(byte[] data, int valueIndex, 540f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int length, int[] colorArray, int bits) { 541f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (0 == (8 % bits)) { 542f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG, "not odd number of color"); 543f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return mapTo2OrderBitColor(data, valueIndex, length, colorArray, 544f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bits); 545f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 546f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 547f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] resultArray = new int[length]; 548f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // TODO fix me: 549f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return resultArray; 550f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 551f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 552f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold private static int[] getCLUT(byte[] rawData, int offset, int number) { 553f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (null == rawData) { 554f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return null; 555f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 556f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 557f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] result = new int[number]; 558f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int endIndex = offset + (number * 3); // 1 color use 3 bytes 559f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int valueIndex = offset; 560f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int colorIndex = 0; 561f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int alpha = 0xff << 24; 562f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold do { 563f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold result[colorIndex++] = alpha 564f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | ((rawData[valueIndex++] & 0xFF) << 16) 565f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | ((rawData[valueIndex++] & 0xFF) << 8) 566f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | ((rawData[valueIndex++] & 0xFF)); 567f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } while (valueIndex < endIndex); 568f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return result; 569f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 570f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold} 571