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