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 35a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun // A table mapping from a number to a hex character for fast encoding hex strings. 36a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun private static final char[] HEX_CHARS = { 37a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 38a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun }; 39a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 40a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 41f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 42f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Many fields in GSM SIM's are stored as nibble-swizzled BCD 43f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 44f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Assumes left-justified field that may be padded right with 0xf 45f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * values. 46f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 47f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Stops on invalid BCD value, returning string so far 48f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 49f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 50f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bcdToString(byte[] data, int offset, int length) { 51f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(length*2); 52f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 53f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i = offset ; i < offset + length ; i++) { 54f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int v; 55f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 56f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = data[i] & 0xf; 57f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v > 9) break; 58f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char)('0' + v)); 59f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 60f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = (data[i] >> 4) & 0xf; 61f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // Some PLMNs have 'f' as high nibble, ignore it 62f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v == 0xf) continue; 63f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v > 9) break; 64f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char)('0' + v)); 65f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 66f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 67f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 68f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 69f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 70f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 71a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts a bcd byte array to String with offset 0 and byte array length. 72a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 73a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static String bcdToString(byte[] data) { 74a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return bcdToString(data, 0, data.length); 75a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 76a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 77a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 78a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts BCD string to bytes. 79a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 80a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param bcd This should have an even length. If not, an "0" will be appended to the string. 81a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 82a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static byte[] bcdToBytes(String bcd) { 83a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun byte[] output = new byte[(bcd.length() + 1) / 2]; 84a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun bcdToBytes(bcd, output); 85a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return output; 86a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 87a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 88a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 89a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts BCD string to bytes and put it into the given byte array. 90a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 91a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param bcd This should have an even length. If not, an "0" will be appended to the string. 92a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param bytes If the array size is less than needed, the rest of the BCD string isn't be 93a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * converted. If the array size is more than needed, the rest of array remains unchanged. 94a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 95a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static void bcdToBytes(String bcd, byte[] bytes) { 96a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (bcd.length() % 2 != 0) { 97a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun bcd += "0"; 98a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 99a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun int size = Math.min(bytes.length * 2, bcd.length()); 100a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun for (int i = 0, j = 0; i + 1 < size; i += 2, j++) { 101a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun bytes[j] = (byte) (charToByte(bcd.charAt(i + 1)) << 4 | charToByte(bcd.charAt(i))); 102a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 103a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 104a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 105a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 106f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3 107f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Returns a concatenated string of MCC+MNC, stripping 1088cd6dad0052a57b16412087581a40b0df80dd15dkun.tang * all invalid character 'f' 109f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 110f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String bcdPlmnToString(byte[] data, int offset) { 111f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (offset + 3 > data.length) { 112f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return null; 113f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 114f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold byte[] trans = new byte[3]; 115f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold trans[0] = (byte) ((data[0 + offset] << 4) | ((data[0 + offset] >> 4) & 0xF)); 116f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold trans[1] = (byte) ((data[1 + offset] << 4) | (data[2 + offset] & 0xF)); 117f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold trans[2] = (byte) ((data[2 + offset] & 0xF0) | ((data[1 + offset] >> 4) & 0xF)); 118f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold String ret = bytesToHexString(trans); 119f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 1208cd6dad0052a57b16412087581a40b0df80dd15dkun.tang // For a valid plmn we trim all character 'f' 1218cd6dad0052a57b16412087581a40b0df80dd15dkun.tang if (ret.contains("f")) { 1228cd6dad0052a57b16412087581a40b0df80dd15dkun.tang ret = ret.replaceAll("f", ""); 123f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 124f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 125f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 126f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 127f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 128f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH 129f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 130f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 131f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bchToString(byte[] data, int offset, int length) { 132f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(length*2); 133f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 134f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i = offset ; i < offset + length ; i++) { 135f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int v; 136f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 137f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = data[i] & 0xf; 138a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun ret.append(HEX_CHARS[v]); 139f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 140f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = (data[i] >> 4) & 0xf; 141a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun ret.append(HEX_CHARS[v]); 142f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 143f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 144f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 145f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 146f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 147f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 148f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Decode cdma byte into String. 149f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 150f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 151f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold cdmaBcdToString(byte[] data, int offset, int length) { 152f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(length); 153f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 154f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int count = 0; 155f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i = offset; count < length; i++) { 156f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int v; 157f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = data[i] & 0xf; 158f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v > 9) v = 0; 159f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char)('0' + v)); 160f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 161f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (++count == length) break; 162f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 163f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold v = (data[i] >> 4) & 0xf; 164f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (v > 9) v = 0; 165f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char)('0' + v)); 166f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ++count; 167f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 168f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 169f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 170f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 171f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 172f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Decodes a GSM-style BCD byte, returning an int ranging from 0-99. 173f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 174f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * In GSM land, the least significant BCD digit is stored in the most 175f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * significant nibble. 176f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 177f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Out-of-range digits are treated as 0 for the sake of the time stamp, 178f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * because of this: 179f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 180f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * TS 23.040 section 9.2.3.11 181f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * "if the MS receives a non-integer value in the SCTS, it shall 182f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * assume the digit is set to 0 but shall store the entire field 183f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * exactly as received" 184f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 185f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static int 186f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold gsmBcdByteToInt(byte b) { 187f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int ret = 0; 188f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 189f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // treat out-of-range BCD values as 0 190f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((b & 0xf0) <= 0x90) { 191f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = (b >> 4) & 0xf; 192f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 193f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 194f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((b & 0x0f) <= 0x09) { 195f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret += (b & 0xf) * 10; 196f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 197f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 198f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 199f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 200f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 201f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 202f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Decodes a CDMA style BCD byte like {@link #gsmBcdByteToInt}, but 203f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * opposite nibble format. The least significant BCD digit 204f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * is in the least significant nibble and the most significant 205f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * is in the most significant nibble. 206f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 207f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static int 208f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold cdmaBcdByteToInt(byte b) { 209f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int ret = 0; 210f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 211f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // treat out-of-range BCD values as 0 212f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((b & 0xf0) <= 0x90) { 213f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = ((b >> 4) & 0xf) * 10; 214f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 215f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 216f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((b & 0x0f) <= 0x09) { 217f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret += (b & 0xf); 218f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 219f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 220f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 221f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 222f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 223f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 224f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Decodes a string field that's formatted like the EF[ADN] alpha 225f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * identifier 226f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 227f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * From TS 51.011 10.5.1: 228f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Coding: 229f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * this alpha tagging shall use either 230f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * - the SMS default 7 bit coded alphabet as defined in 231f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * TS 23.038 [12] with bit 8 set to 0. The alpha identifier 232f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * shall be left justified. Unused bytes shall be set to 'FF'; or 233f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * - one of the UCS2 coded options as defined in annex B. 234f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 235f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Annex B from TS 11.11 V8.13.0: 236f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 1) If the first octet in the alpha string is '80', then the 237f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * remaining octets are 16 bit UCS2 characters ... 238f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 2) if the first octet in the alpha string is '81', then the 239f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * second octet contains a value indicating the number of 240f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * characters in the string, and the third octet contains an 241f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 8 bit number which defines bits 15 to 8 of a 16 bit 242f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * base pointer, where bit 16 is set to zero and bits 7 to 1 243f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * are also set to zero. These sixteen bits constitute a 244f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * base pointer to a "half page" in the UCS2 code space, to be 245f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * used with some or all of the remaining octets in the string. 246f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * The fourth and subsequent octets contain codings as follows: 247f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * If bit 8 of the octet is set to zero, the remaining 7 bits 248f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * of the octet contain a GSM Default Alphabet character, 249f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * whereas if bit 8 of the octet is set to one, then the 250f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * remaining seven bits are an offset value added to the 251f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 16 bit base pointer defined earlier... 252f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 3) If the first octet of the alpha string is set to '82', then 253f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * the second octet contains a value indicating the number of 254f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * characters in the string, and the third and fourth octets 255f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * contain a 16 bit number which defines the complete 16 bit 256f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * base pointer to a "half page" in the UCS2 code space... 257f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 258f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 259f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold adnStringFieldToString(byte[] data, int offset, int length) { 260f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (length == 0) { 261f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ""; 262f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 263f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (length >= 1) { 264f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (data[offset] == (byte) 0x80) { 265f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int ucslen = (length - 1) / 2; 266f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold String ret = null; 267f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 268f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold try { 269f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = new String(data, offset + 1, ucslen * 2, "utf-16be"); 270f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } catch (UnsupportedEncodingException ex) { 271f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException", 272f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ex); 273f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 274f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 275f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (ret != null) { 276f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // trim off trailing FFFF characters 277f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 278f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ucslen = ret.length(); 279f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (ucslen > 0 && ret.charAt(ucslen - 1) == '\uFFFF') 280f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ucslen--; 281f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 282f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.substring(0, ucslen); 283f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 284f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 285f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 286f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 287f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold boolean isucs2 = false; 288f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold char base = '\0'; 289f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int len = 0; 290f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 291f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (length >= 3 && data[offset] == (byte) 0x81) { 292f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len = data[offset + 1] & 0xFF; 293f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (len > length - 3) 294f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len = length - 3; 295f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 296f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold base = (char) ((data[offset + 2] & 0xFF) << 7); 297f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset += 3; 298f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold isucs2 = true; 299f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } else if (length >= 4 && data[offset] == (byte) 0x82) { 300f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len = data[offset + 1] & 0xFF; 301f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (len > length - 4) 302f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len = length - 4; 303f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 304f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold base = (char) (((data[offset + 2] & 0xFF) << 8) | 305f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold (data[offset + 3] & 0xFF)); 306f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset += 4; 307f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold isucs2 = true; 308f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 309f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 310f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (isucs2) { 311f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(); 312f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 313f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (len > 0) { 314f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // UCS2 subset case 315f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 316f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (data[offset] < 0) { 317f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append((char) (base + (data[offset] & 0x7F))); 318f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset++; 319f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len--; 320f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 321f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 322f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // GSM character set case 323f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 324f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int count = 0; 325f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (count < len && data[offset + count] >= 0) 326f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold count++; 327f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 328f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret.append(GsmAlphabet.gsm8BitUnpackedToString(data, 329f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset, count)); 330f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 331f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset += count; 332f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold len -= count; 333f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 334f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 335f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 336f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 337f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 338f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Resources resource = Resources.getSystem(); 339f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold String defaultCharset = ""; 340f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold try { 341f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold defaultCharset = 342f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold resource.getString(com.android.internal.R.string.gsm_alphabet_default_charset); 343f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } catch (NotFoundException e) { 344f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // Ignore Exception and defaultCharset is set to a empty string. 345f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 346f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim()); 347f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 348f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 349a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static int 350f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold hexCharToInt(char c) { 351f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (c >= '0' && c <= '9') return (c - '0'); 352f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (c >= 'A' && c <= 'F') return (c - 'A' + 10); 353f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (c >= 'a' && c <= 'f') return (c - 'a' + 10); 354f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 355f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold throw new RuntimeException ("invalid hex char '" + c + "'"); 356f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 357f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 358f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 359f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Converts a hex String to a byte array. 360f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 361f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param s A string of hexadecimal characters, must be an even number of 362f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * chars long 363f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 364f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @return byte array representation 365f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 366f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @throws RuntimeException on invalid format 367f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 368f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static byte[] 369f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold hexStringToBytes(String s) { 370f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold byte[] ret; 371f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 372f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (s == null) return null; 373f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 374f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int sz = s.length(); 375f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 376f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = new byte[sz/2]; 377f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 378f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i=0 ; i <sz ; i+=2) { 379f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) 380f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | hexCharToInt(s.charAt(i+1))); 381f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 382f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 383f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 384f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 385f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 386f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 387f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 388f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Converts a byte array into a String of hexadecimal characters. 389f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 390f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param bytes an array of bytes 391f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 392f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @return hex string representation of bytes array 393f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 394f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 395f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bytesToHexString(byte[] bytes) { 396f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (bytes == null) return null; 397f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 398f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold StringBuilder ret = new StringBuilder(2*bytes.length); 399f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 400f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int i = 0 ; i < bytes.length ; i++) { 401f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int b; 402f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 403f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold b = 0x0f & (bytes[i] >> 4); 404f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 405a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun ret.append(HEX_CHARS[b]); 406f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 407f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold b = 0x0f & bytes[i]; 408f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 409a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun ret.append(HEX_CHARS[b]); 410f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 411f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 412f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret.toString(); 413f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 414f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 415f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 416f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 417f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Convert a TS 24.008 Section 10.5.3.5a Network Name field to a string 418f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * "offset" points to "octet 3", the coding scheme byte 419f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * empty string returned on decode error 420f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 421f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static String 422f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold networkNameToString(byte[] data, int offset, int length) { 423f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold String ret; 424f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 425f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((data[offset] & 0x80) != 0x80 || length < 1) { 426f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ""; 427f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 428f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 429f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold switch ((data[offset] >>> 4) & 0x7) { 430f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 0: 431f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // SMS character set 432f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int countSeptets; 433f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int unusedBits = data[offset] & 7; 434f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold countSeptets = (((length - 1) * 8) - unusedBits) / 7 ; 435f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets); 436f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 437f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 1: 438f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // UCS2 439f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold try { 440f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = new String(data, 441f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold offset + 1, length - 1, "utf-16"); 442f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } catch (UnsupportedEncodingException ex) { 443f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = ""; 444f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG,"implausible UnsupportedEncodingException", ex); 445f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 446f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 447f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 448f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // unsupported encoding 449f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold default: 450f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold ret = ""; 451f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 452f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 453f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 454f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // "Add CI" 455f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // "The MS should add the letters for the Country's Initials and 456f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // a separator (e.g. a space) to the text string" 457f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 458f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if ((data[offset] & 0x40) != 0) { 459f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // FIXME(mkf) add country initials here 460f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 461f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 462f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return ret; 463f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 464f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 465f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 466f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * Convert a TS 131.102 image instance of code scheme '11' into Bitmap 467f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param data The raw data 468f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param length The length of image body 469f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @return The bitmap 470f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 471f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static Bitmap parseToBnW(byte[] data, int length){ 472f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int valueIndex = 0; 473f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int width = data[valueIndex++] & 0xFF; 474f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int height = data[valueIndex++] & 0xFF; 475f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int numOfPixels = width*height; 476f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 477f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] pixels = new int[numOfPixels]; 478f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 479f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int pixelIndex = 0; 480f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int bitIndex = 7; 481f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold byte currentByte = 0x00; 482f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (pixelIndex < numOfPixels) { 483f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // reassign data and index for every byte (8 bits). 484f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (pixelIndex % 8 == 0) { 485f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold currentByte = data[valueIndex++]; 486f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bitIndex = 7; 487f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 488f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold pixels[pixelIndex++] = bitToRGB((currentByte >> bitIndex-- ) & 0x01); 489f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 490f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 491f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (pixelIndex != numOfPixels) { 492f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG, "parse end and size error"); 493f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 494f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); 495f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 496f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 497f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold private static int bitToRGB(int bit){ 498f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if(bit == 1){ 499f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return Color.WHITE; 500f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } else { 501f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return Color.BLACK; 502f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 503f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 504f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 505f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold /** 506f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * a TS 131.102 image instance of code scheme '11' into color Bitmap 507f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * 508f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param data The raw data 509f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param length the length of image body 510f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @param transparency with or without transparency 511f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold * @return The color bitmap 512f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold */ 513f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold public static Bitmap parseToRGB(byte[] data, int length, 514f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold boolean transparency) { 515f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int valueIndex = 0; 516f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int width = data[valueIndex++] & 0xFF; 517f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int height = data[valueIndex++] & 0xFF; 518f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int bits = data[valueIndex++] & 0xFF; 519f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int colorNumber = data[valueIndex++] & 0xFF; 520f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int clutOffset = ((data[valueIndex++] & 0xFF) << 8) 521f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | (data[valueIndex++] & 0xFF); 522f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 523f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber); 524f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (true == transparency) { 525f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold colorIndexArray[colorNumber - 1] = Color.TRANSPARENT; 526f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 527f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 528f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] resultArray = null; 529f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (0 == (8 % bits)) { 530f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold resultArray = mapTo2OrderBitColor(data, valueIndex, 531f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold (width * height), colorIndexArray, bits); 532f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } else { 533f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold resultArray = mapToNon2OrderBitColor(data, valueIndex, 534f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold (width * height), colorIndexArray, bits); 535f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 536f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 537f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return Bitmap.createBitmap(resultArray, width, height, 538f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Bitmap.Config.RGB_565); 539f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 540f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 541f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold private static int[] mapTo2OrderBitColor(byte[] data, int valueIndex, 542f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int length, int[] colorArray, int bits) { 543f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (0 != (8 % bits)) { 544f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG, "not event number of color"); 545f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return mapToNon2OrderBitColor(data, valueIndex, length, colorArray, 546f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bits); 547f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 548f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 549f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int mask = 0x01; 550f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold switch (bits) { 551f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 1: 552f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold mask = 0x01; 553f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 554f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 2: 555f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold mask = 0x03; 556f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 557f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 4: 558f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold mask = 0x0F; 559f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 560f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold case 8: 561f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold mask = 0xFF; 562f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold break; 563f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 564f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 565f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] resultArray = new int[length]; 566f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int resultIndex = 0; 567f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int run = 8 / bits; 568f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold while (resultIndex < length) { 569f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold byte tempByte = data[valueIndex++]; 570f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold for (int runIndex = 0; runIndex < run; ++runIndex) { 571f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int offset = run - runIndex - 1; 572f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold resultArray[resultIndex++] = colorArray[(tempByte >> (offset * bits)) 573f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold & mask]; 574f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 575f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 576f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return resultArray; 577f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 578f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 579f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold private static int[] mapToNon2OrderBitColor(byte[] data, int valueIndex, 580f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int length, int[] colorArray, int bits) { 581f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (0 == (8 % bits)) { 582f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold Rlog.e(LOG_TAG, "not odd number of color"); 583f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return mapTo2OrderBitColor(data, valueIndex, length, colorArray, 584f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold bits); 585f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 586f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 587f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] resultArray = new int[length]; 588f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold // TODO fix me: 589f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return resultArray; 590f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 591f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 592f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold private static int[] getCLUT(byte[] rawData, int offset, int number) { 593f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold if (null == rawData) { 594f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return null; 595f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 596f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold 597f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int[] result = new int[number]; 598f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int endIndex = offset + (number * 3); // 1 color use 3 bytes 599f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int valueIndex = offset; 600f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int colorIndex = 0; 601f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold int alpha = 0xff << 24; 602f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold do { 603f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold result[colorIndex++] = alpha 604f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | ((rawData[valueIndex++] & 0xFF) << 16) 605f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | ((rawData[valueIndex++] & 0xFF) << 8) 606f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold | ((rawData[valueIndex++] & 0xFF)); 607f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } while (valueIndex < endIndex); 608f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold return result; 609f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold } 610cf94c67dc0e8aff3cdb069d382a64c4e1ea36ec9Yujing Gu 611cf94c67dc0e8aff3cdb069d382a64c4e1ea36ec9Yujing Gu public static String getDecimalSubstring(String iccId) { 612cf94c67dc0e8aff3cdb069d382a64c4e1ea36ec9Yujing Gu int position; 613cf94c67dc0e8aff3cdb069d382a64c4e1ea36ec9Yujing Gu for (position = 0; position < iccId.length(); position ++) { 614cf94c67dc0e8aff3cdb069d382a64c4e1ea36ec9Yujing Gu if (!Character.isDigit(iccId.charAt(position))) break; 615cf94c67dc0e8aff3cdb069d382a64c4e1ea36ec9Yujing Gu } 616cf94c67dc0e8aff3cdb069d382a64c4e1ea36ec9Yujing Gu return iccId.substring( 0, position ); 617cf94c67dc0e8aff3cdb069d382a64c4e1ea36ec9Yujing Gu } 618a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 619a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 620a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts a series of bytes to an integer. This method currently only supports positive 32-bit 621a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * integers. 622a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 623a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param src The source bytes. 624a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param offset The position of the first byte of the data to be converted. The data is base 625a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 256 with the most significant digit first. 626a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param length The length of the data to be converted. It must be <= 4. 627a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IllegalArgumentException If {@code length} is bigger than 4 or {@code src} cannot be 628a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * parsed as a positive integer. 629a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IndexOutOfBoundsException If the range defined by {@code offset} and {@code length} 630a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * exceeds the bounds of {@code src}. 631a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 632a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static int bytesToInt(byte[] src, int offset, int length) { 633a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (length > 4) { 634a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IllegalArgumentException( 635a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun "length must be <= 4 (only 32-bit integer supported): " + length); 636a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 637a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (offset < 0 || length < 0 || offset + length > src.length) { 638a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IndexOutOfBoundsException( 639a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun "Out of the bounds: src=[" 640a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + src.length 641a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + "], offset=" 642a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + offset 643a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + ", length=" 644a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + length); 645a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 646a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun int result = 0; 647a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun for (int i = 0; i < length; i++) { 648a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun result = (result << 8) | (src[offset + i] & 0xFF); 649a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 650a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (result < 0) { 651a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IllegalArgumentException( 652a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun "src cannot be parsed as a positive integer: " + result); 653a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 654a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return result; 655a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 656a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 657a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 658a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts a series of bytes to a raw long variable which can be both positive and negative. 659a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * This method currently only supports 64-bit long variable. 660a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 661a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param src The source bytes. 662a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param offset The position of the first byte of the data to be converted. The data is base 663a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 256 with the most significant digit first. 664a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param length The length of the data to be converted. It must be <= 8. 665a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IllegalArgumentException If {@code length} is bigger than 8. 666a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IndexOutOfBoundsException If the range defined by {@code offset} and {@code length} 667a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * exceeds the bounds of {@code src}. 668a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 669a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static long bytesToRawLong(byte[] src, int offset, int length) { 670a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (length > 8) { 671a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IllegalArgumentException( 672a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun "length must be <= 8 (only 64-bit long supported): " + length); 673a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 674a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (offset < 0 || length < 0 || offset + length > src.length) { 675a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IndexOutOfBoundsException( 676a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun "Out of the bounds: src=[" 677a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + src.length 678a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + "], offset=" 679a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + offset 680a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + ", length=" 681a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun + length); 682a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 683a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun long result = 0; 684a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun for (int i = 0; i < length; i++) { 685a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun result = (result << 8) | (src[offset + i] & 0xFF); 686a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 687a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return result; 688a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 689a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 690a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 691a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts an integer to a new byte array with base 256 and the most significant digit first. 692a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 693a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IllegalArgumentException If {@code value} is negative. 694a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 695a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static byte[] unsignedIntToBytes(int value) { 696a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value < 0) { 697a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IllegalArgumentException("value must be 0 or positive: " + value); 698a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 699a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun byte[] bytes = new byte[byteNumForUnsignedInt(value)]; 700a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun unsignedIntToBytes(value, bytes, 0); 701a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return bytes; 702a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 703a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 704a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 705a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts an integer to a new byte array with base 256 and the most significant digit first. 706a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * The first byte's highest bit is used for sign. If the most significant digit is larger than 707a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 127, an extra byte (0) will be prepended before it. This method currently doesn't support 708a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * negative values. 709a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 710a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IllegalArgumentException If {@code value} is negative. 711a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 712a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static byte[] signedIntToBytes(int value) { 713a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value < 0) { 714a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IllegalArgumentException("value must be 0 or positive: " + value); 715a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 716a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun byte[] bytes = new byte[byteNumForSignedInt(value)]; 717a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun signedIntToBytes(value, bytes, 0); 718a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return bytes; 719a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 720a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 721a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 722a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts an integer to a series of bytes with base 256 and the most significant digit first. 723a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 724a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param value The integer to be converted. 725a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param dest The destination byte array. 726a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @param offset The start offset of the byte array. 727a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @return The number of byte needeed. 728a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IllegalArgumentException If {@code value} is negative. 729a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IndexOutOfBoundsException If {@code offset} exceeds the bounds of {@code dest}. 730a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 731a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static int unsignedIntToBytes(int value, byte[] dest, int offset) { 732a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return intToBytes(value, dest, offset, false); 733a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 734a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 735a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 736a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts an integer to a series of bytes with base 256 and the most significant digit first. 737a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * The first byte's highest bit is used for sign. If the most significant digit is larger than 738a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 127, an extra byte (0) will be prepended before it. This method currently doesn't support 739a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * negative values. 740a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 741a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IllegalArgumentException If {@code value} is negative. 742a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IndexOutOfBoundsException If {@code offset} exceeds the bounds of {@code dest}. 743a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 744a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static int signedIntToBytes(int value, byte[] dest, int offset) { 745a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return intToBytes(value, dest, offset, true); 746a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 747a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 748a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 749a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Calculates the number of required bytes to represent {@code value}. The bytes will be base 750a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 256 with the most significant digit first. 751a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 752a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IllegalArgumentException If {@code value} is negative. 753a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 754a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static int byteNumForUnsignedInt(int value) { 755a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return byteNumForInt(value, false); 756a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 757a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 758a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 759a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Calculates the number of required bytes to represent {@code value}. The bytes will be base 760a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 256 with the most significant digit first. If the most significant digit is larger than 127, 761a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * an extra byte (0) will be prepended before it. This method currently only supports positive 762a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * integers. 763a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * 764a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * @throws IllegalArgumentException If {@code value} is negative. 765a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 766a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static int byteNumForSignedInt(int value) { 767a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return byteNumForInt(value, true); 768a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 769a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 770a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun private static int intToBytes(int value, byte[] dest, int offset, boolean signed) { 771a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun int l = byteNumForInt(value, signed); 772a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (offset < 0 || offset + l > dest.length) { 773a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IndexOutOfBoundsException("Not enough space to write. Required bytes: " + l); 774a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 775a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun for (int i = l - 1, v = value; i >= 0; i--, v >>>= 8) { 776a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun byte b = (byte) (v & 0xFF); 777a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun dest[offset + i] = b; 778a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 779a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return l; 780a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 781a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 782a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun private static int byteNumForInt(int value, boolean signed) { 783a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value < 0) { 784a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun throw new IllegalArgumentException("value must be 0 or positive: " + value); 785a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 786a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (signed) { 787a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value <= 0x7F) { 788a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 1; 789a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 790a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value <= 0x7FFF) { 791a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 2; 792a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 793a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value <= 0x7FFFFF) { 794a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 3; 795a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 796a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } else { 797a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value <= 0xFF) { 798a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 1; 799a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 800a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value <= 0xFFFF) { 801a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 2; 802a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 803a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (value <= 0xFFFFFF) { 804a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 3; 805a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 806a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 807a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 4; 808a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 809a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 810a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 811a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 812a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Counts the number of trailing zero bits of a byte. 813a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 814a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static byte countTrailingZeros(byte b) { 815a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (b == 0) { 816a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 8; 817a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 818a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun int v = b & 0xFF; 819a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun byte c = 7; 820a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if ((v & 0x0F) != 0) { 821a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun c -= 4; 822a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 823a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if ((v & 0x33) != 0) { 824a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun c -= 2; 825a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 826a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if ((v & 0x55) != 0) { 827a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun c -= 1; 828a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 829a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return c; 830a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 831a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 832a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 833a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts a byte to a hex string. 834a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 835a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun public static String byteToHex(byte b) { 836a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return new String(new char[] {HEX_CHARS[(b & 0xFF) >>> 4], HEX_CHARS[b & 0xF]}); 837a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 838a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun 839a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun /** 840b40a26c43d30f475682b59dbbe404bae932b68b0Jun Yin * Strip all the trailing 'F' characters of a string, e.g., an ICCID. 841b40a26c43d30f475682b59dbbe404bae932b68b0Jun Yin */ 842b40a26c43d30f475682b59dbbe404bae932b68b0Jun Yin public static String stripTrailingFs(String s) { 843b40a26c43d30f475682b59dbbe404bae932b68b0Jun Yin return s == null ? null : s.replaceAll("(?i)f*$", ""); 844b40a26c43d30f475682b59dbbe404bae932b68b0Jun Yin } 845b40a26c43d30f475682b59dbbe404bae932b68b0Jun Yin 846b40a26c43d30f475682b59dbbe404bae932b68b0Jun Yin /** 847a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * Converts a character of [0-9a-aA-F] to its hex value in a byte. If the character is not a 848a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun * hex number, 0 will be returned. 849a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun */ 850a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun private static byte charToByte(char c) { 851a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun if (c >= 0x30 && c <= 0x39) { 852a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return (byte) (c - 0x30); 853a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } else if (c >= 0x41 && c <= 0x46) { 854a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return (byte) (c - 0x37); 855a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } else if (c >= 0x61 && c <= 0x66) { 856a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return (byte) (c - 0x57); 857a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 858a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun return 0; 859a2b23916c08a3cca55206510fda6e80360d5b4aaHolly Jiuyu Sun } 860f3e659e2865fe52af5a87efb52299b81005aeb17Nathan Harold} 861