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