10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2006 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources.NotFoundException;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.Bitmap;
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.graphics.Color;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.Log;
240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet;
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.UnsupportedEncodingException;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.nio.ByteBuffer;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.nio.charset.Charset;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/**
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Various methods, useful for dealing with SIM data.
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class IccUtils {
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final String LOG_TAG="IccUtils";
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Many fields in GSM SIM's are stored as nibble-swizzled BCD
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Assumes left-justified field that may be padded right with 0xf
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * values.
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Stops on invalid BCD value, returning string so far
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static String
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    bcdToString(byte[] data, int offset, int length) {
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        StringBuilder ret = new StringBuilder(length*2);
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = offset ; i < offset + length ; i++) {
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte b;
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int v;
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            v = data[i] & 0xf;
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (v > 9)  break;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret.append((char)('0' + v));
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            v = (data[i] >> 4) & 0xf;
570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Some PLMNs have 'f' as high nibble, ignore it
580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (v == 0xf) continue;
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (v > 9)  break;
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret.append((char)('0' + v));
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ret.toString();
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Decode cdma byte into String.
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static String
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    cdmaBcdToString(byte[] data, int offset, int length) {
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        StringBuilder ret = new StringBuilder(length);
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int count = 0;
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = offset; count < length; i++) {
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int v;
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            v = data[i] & 0xf;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (v > 9)  v = 0;
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret.append((char)('0' + v));
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (++count == length) break;
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            v = (data[i] >> 4) & 0xf;
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (v > 9)  v = 0;
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret.append((char)('0' + v));
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ++count;
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ret.toString();
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Decodes a GSM-style BCD byte, returning an int ranging from 0-99.
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * In GSM land, the least significant BCD digit is stored in the most
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * significant nibble.
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Out-of-range digits are treated as 0 for the sake of the time stamp,
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * because of this:
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * TS 23.040 section 9.2.3.11
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * "if the MS receives a non-integer value in the SCTS, it shall
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * assume the digit is set to 0 but shall store the entire field
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * exactly as received"
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static int
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    gsmBcdByteToInt(byte b) {
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int ret = 0;
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // treat out-of-range BCD values as 0
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((b & 0xf0) <= 0x90) {
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret = (b >> 4) & 0xf;
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((b & 0x0f) <= 0x09) {
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret +=  (b & 0xf) * 10;
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ret;
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Decodes a CDMA style BCD byte like {@link gsmBcdByteToInt}, but
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * opposite nibble format. The least significant BCD digit
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * is in the least significant nibble and the most significant
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * is in the most significant nibble.
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static int
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    cdmaBcdByteToInt(byte b) {
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int ret = 0;
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // treat out-of-range BCD values as 0
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((b & 0xf0) <= 0x90) {
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret = ((b >> 4) & 0xf) * 10;
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((b & 0x0f) <= 0x09) {
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret +=  (b & 0xf);
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ret;
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Decodes a string field that's formatted like the EF[ADN] alpha
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * identifier
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * From TS 51.011 10.5.1:
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   Coding:
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       this alpha tagging shall use either
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *      -    the SMS default 7 bit coded alphabet as defined in
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          TS 23.038 [12] with bit 8 set to 0. The alpha identifier
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          shall be left justified. Unused bytes shall be set to 'FF'; or
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *      -    one of the UCS2 coded options as defined in annex B.
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Annex B from TS 11.11 V8.13.0:
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *      1)  If the first octet in the alpha string is '80', then the
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          remaining octets are 16 bit UCS2 characters ...
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *      2)  if the first octet in the alpha string is '81', then the
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          second octet contains a value indicating the number of
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          characters in the string, and the third octet contains an
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          8 bit number which defines bits 15 to 8 of a 16 bit
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          base pointer, where bit 16 is set to zero and bits 7 to 1
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          are also set to zero.  These sixteen bits constitute a
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          base pointer to a "half page" in the UCS2 code space, to be
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          used with some or all of the remaining octets in the string.
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          The fourth and subsequent octets contain codings as follows:
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          If bit 8 of the octet is set to zero, the remaining 7 bits
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          of the octet contain a GSM Default Alphabet character,
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          whereas if bit 8 of the octet is set to one, then the
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          remaining seven bits are an offset value added to the
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          16 bit base pointer defined earlier...
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *      3)  If the first octet of the alpha string is set to '82', then
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          the second octet contains a value indicating the number of
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          characters in the string, and the third and fourth octets
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          contain a 16 bit number which defines the complete 16 bit
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          base pointer to a "half page" in the UCS2 code space...
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static String
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    adnStringFieldToString(byte[] data, int offset, int length) {
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (length == 0) {
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return "";
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (length >= 1) {
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (data[offset] == (byte) 0x80) {
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int ucslen = (length - 1) / 2;
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                String ret = null;
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ret = new String(data, offset + 1, ucslen * 2, "utf-16be");
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (UnsupportedEncodingException ex) {
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Log.e(LOG_TAG, "implausible UnsupportedEncodingException",
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                          ex);
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ret != null) {
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    // trim off trailing FFFF characters
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ucslen = ret.length();
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    while (ucslen > 0 && ret.charAt(ucslen - 1) == '\uFFFF')
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        ucslen--;
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    return ret.substring(0, ucslen);
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean isucs2 = false;
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        char base = '\0';
2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int len = 0;
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (length >= 3 && data[offset] == (byte) 0x81) {
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            len = data[offset + 1] & 0xFF;
2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (len > length - 3)
2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                len = length - 3;
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            base = (char) ((data[offset + 2] & 0xFF) << 7);
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            offset += 3;
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            isucs2 = true;
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else if (length >= 4 && data[offset] == (byte) 0x82) {
2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            len = data[offset + 1] & 0xFF;
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (len > length - 4)
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                len = length - 4;
2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            base = (char) (((data[offset + 2] & 0xFF) << 8) |
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            (data[offset + 3] & 0xFF));
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            offset += 4;
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            isucs2 = true;
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isucs2) {
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            StringBuilder ret = new StringBuilder();
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            while (len > 0) {
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // UCS2 subset case
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (data[offset] < 0) {
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ret.append((char) (base + (data[offset] & 0x7F)));
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    offset++;
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    len--;
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // GSM character set case
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int count = 0;
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                while (count < len && data[offset + count] >= 0)
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    count++;
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ret.append(GsmAlphabet.gsm8BitUnpackedToString(data,
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                           offset, count));
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                offset += count;
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                len -= count;
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return ret.toString();
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources resource = Resources.getSystem();
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String defaultCharset = "";
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            defaultCharset =
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    resource.getString(com.android.internal.R.string.gsm_alphabet_default_charset);
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (NotFoundException e) {
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Ignore Exception and defaultCharset is set to a empty string.
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim());
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static int
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    hexCharToInt(char c) {
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (c >= '0' && c <= '9') return (c - '0');
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throw new RuntimeException ("invalid hex char '" + c + "'");
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Converts a hex String to a byte array.
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param s A string of hexadecimal characters, must be an even number of
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          chars long
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return byte array representation
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @throws RuntimeException on invalid format
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static byte[]
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    hexStringToBytes(String s) {
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] ret;
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (s == null) return null;
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int sz = s.length();
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ret = new byte[sz/2];
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i=0 ; i <sz ; i+=2) {
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4)
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                | hexCharToInt(s.charAt(i+1)));
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ret;
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Converts a byte array into a String of hexadecimal characters.
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param bytes an array of bytes
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return hex string representation of bytes array
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static String
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    bytesToHexString(byte[] bytes) {
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (bytes == null) return null;
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        StringBuilder ret = new StringBuilder(2*bytes.length);
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0 ; i < bytes.length ; i++) {
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int b;
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            b = 0x0f & (bytes[i] >> 4);
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret.append("0123456789abcdef".charAt(b));
3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            b = 0x0f & bytes[i];
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ret.append("0123456789abcdef".charAt(b));
3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ret.toString();
3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Convert a TS 24.008 Section 10.5.3.5a Network Name field to a string
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * "offset" points to "octet 3", the coding scheme byte
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * empty string returned on decode error
3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static String
3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    networkNameToString(byte[] data, int offset, int length) {
3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String ret;
3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((data[offset] & 0x80) != 0x80 || length < 1) {
3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return "";
3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch ((data[offset] >>> 4) & 0x7) {
3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case 0:
3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // SMS character set
3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int countSeptets;
3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int unusedBits = data[offset] & 7;
3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                countSeptets = (((length - 1) * 8) - unusedBits) / 7 ;
3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ret =  GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets);
3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case 1:
3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // UCS2
3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ret = new String(data,
3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            offset + 1, length - 1, "utf-16");
3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (UnsupportedEncodingException ex) {
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ret = "";
3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Log.e(LOG_TAG,"implausible UnsupportedEncodingException", ex);
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // unsupported encoding
3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            default:
3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ret = "";
3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // "Add CI"
3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // "The MS should add the letters for the Country's Initials and
3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        //  a separator (e.g. a space) to the text string"
3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((data[offset] & 0x40) != 0) {
3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // FIXME(mkf) add country initials here
3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ret;
3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Convert a TS 131.102 image instance of code scheme '11' into Bitmap
3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data The raw data
3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param length The length of image body
3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return The bitmap
3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static Bitmap parseToBnW(byte[] data, int length){
3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int valueIndex = 0;
3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int width = data[valueIndex++] & 0xFF;
3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int height = data[valueIndex++] & 0xFF;
3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int numOfPixels = width*height;
3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int[] pixels = new int[numOfPixels];
3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int pixelIndex = 0;
4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int bitIndex = 7;
4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte currentByte = 0x00;
4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        while (pixelIndex < numOfPixels) {
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // reassign data and index for every byte (8 bits).
4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (pixelIndex % 8 == 0) {
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                currentByte = data[valueIndex++];
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                bitIndex = 7;
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            pixels[pixelIndex++] = bitToRGB((currentByte >> bitIndex-- ) & 0x01);
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        };
4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pixelIndex != numOfPixels) {
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(LOG_TAG, "parse end and size error");
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int bitToRGB(int bit){
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if(bit == 1){
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Color.WHITE;
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Color.BLACK;
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * a TS 131.102 image instance of code scheme '11' into color Bitmap
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data The raw data
4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param length the length of image body
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param transparency with or without transparency
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return The color bitmap
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static Bitmap parseToRGB(byte[] data, int length,
4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean transparency) {
4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int valueIndex = 0;
4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int width = data[valueIndex++] & 0xFF;
4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int height = data[valueIndex++] & 0xFF;
4380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int bits = data[valueIndex++] & 0xFF;
4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int colorNumber = data[valueIndex++] & 0xFF;
4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int clutOffset = ((data[valueIndex++] & 0xFF) << 8)
4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                | (data[valueIndex++] & 0xFF);
4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber);
4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (true == transparency) {
4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            colorIndexArray[colorNumber - 1] = Color.TRANSPARENT;
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int[] resultArray = null;
4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (0 == (8 % bits)) {
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            resultArray = mapTo2OrderBitColor(data, valueIndex,
4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    (width * height), colorIndexArray, bits);
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            resultArray = mapToNon2OrderBitColor(data, valueIndex,
4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    (width * height), colorIndexArray, bits);
4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return Bitmap.createBitmap(resultArray, width, height,
4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Bitmap.Config.RGB_565);
4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int[] mapTo2OrderBitColor(byte[] data, int valueIndex,
4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int length, int[] colorArray, int bits) {
4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (0 != (8 % bits)) {
4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(LOG_TAG, "not event number of color");
4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return mapToNon2OrderBitColor(data, valueIndex, length, colorArray,
4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    bits);
4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int mask = 0x01;
4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (bits) {
4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case 1:
4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mask = 0x01;
4730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case 2:
4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mask = 0x03;
4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case 4:
4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mask = 0x0F;
4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case 8:
4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mask = 0xFF;
4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int[] resultArray = new int[length];
4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int resultIndex = 0;
4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int run = 8 / bits;
4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        while (resultIndex < length) {
4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte tempByte = data[valueIndex++];
4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int runIndex = 0; runIndex < run; ++runIndex) {
4910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int offset = run - runIndex - 1;
4920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                resultArray[resultIndex++] = colorArray[(tempByte >> (offset * bits))
4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        & mask];
4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return resultArray;
4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int[] mapToNon2OrderBitColor(byte[] data, int valueIndex,
5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int length, int[] colorArray, int bits) {
5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (0 == (8 % bits)) {
5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(LOG_TAG, "not odd number of color");
5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return mapTo2OrderBitColor(data, valueIndex, length, colorArray,
5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    bits);
5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int[] resultArray = new int[length];
5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // TODO fix me:
5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return resultArray;
5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int[] getCLUT(byte[] rawData, int offset, int number) {
5130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (null == rawData) {
5140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return null;
5150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int[] result = new int[number];
5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int endIndex = offset + (number * 3); // 1 color use 3 bytes
5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int valueIndex = offset;
5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int colorIndex = 0;
5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int alpha = 0xff << 24;
5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        do {
5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            result[colorIndex++] = alpha
5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    | ((rawData[valueIndex++] & 0xFF) << 16)
5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    | ((rawData[valueIndex++] & 0xFF) << 8)
5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    | ((rawData[valueIndex++] & 0xFF));
5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } while (valueIndex < endIndex);
5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return result;
5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
531