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