Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony;
     18 
     19 import java.util.HashMap;
     20 
     21 /**
     22  * Implement the WSP data type decoder.
     23  *
     24  * @hide
     25  */
     26 public class WspTypeDecoder {
     27 
     28     private static final int WAP_PDU_SHORT_LENGTH_MAX = 30;
     29     private static final int WAP_PDU_LENGTH_QUOTE = 31;
     30 
     31     public static final int PDU_TYPE_PUSH = 0x06;
     32     public static final int PDU_TYPE_CONFIRMED_PUSH = 0x07;
     33 
     34     private final static HashMap<Integer, String> WELL_KNOWN_MIME_TYPES =
     35             new HashMap<Integer, String>();
     36 
     37     private final static HashMap<Integer, String> WELL_KNOWN_PARAMETERS =
     38             new HashMap<Integer, String>();
     39 
     40     public static final int PARAMETER_ID_X_WAP_APPLICATION_ID = 0x2f;
     41     private static final int Q_VALUE = 0x00;
     42 
     43     static {
     44         WELL_KNOWN_MIME_TYPES.put(0x00, "*/*");
     45         WELL_KNOWN_MIME_TYPES.put(0x01, "text/*");
     46         WELL_KNOWN_MIME_TYPES.put(0x02, "text/html");
     47         WELL_KNOWN_MIME_TYPES.put(0x03, "text/plain");
     48         WELL_KNOWN_MIME_TYPES.put(0x04, "text/x-hdml");
     49         WELL_KNOWN_MIME_TYPES.put(0x05, "text/x-ttml");
     50         WELL_KNOWN_MIME_TYPES.put(0x06, "text/x-vCalendar");
     51         WELL_KNOWN_MIME_TYPES.put(0x07, "text/x-vCard");
     52         WELL_KNOWN_MIME_TYPES.put(0x08, "text/vnd.wap.wml");
     53         WELL_KNOWN_MIME_TYPES.put(0x09, "text/vnd.wap.wmlscript");
     54         WELL_KNOWN_MIME_TYPES.put(0x0A, "text/vnd.wap.wta-event");
     55         WELL_KNOWN_MIME_TYPES.put(0x0B, "multipart/*");
     56         WELL_KNOWN_MIME_TYPES.put(0x0C, "multipart/mixed");
     57         WELL_KNOWN_MIME_TYPES.put(0x0D, "multipart/form-data");
     58         WELL_KNOWN_MIME_TYPES.put(0x0E, "multipart/byterantes");
     59         WELL_KNOWN_MIME_TYPES.put(0x0F, "multipart/alternative");
     60         WELL_KNOWN_MIME_TYPES.put(0x10, "application/*");
     61         WELL_KNOWN_MIME_TYPES.put(0x11, "application/java-vm");
     62         WELL_KNOWN_MIME_TYPES.put(0x12, "application/x-www-form-urlencoded");
     63         WELL_KNOWN_MIME_TYPES.put(0x13, "application/x-hdmlc");
     64         WELL_KNOWN_MIME_TYPES.put(0x14, "application/vnd.wap.wmlc");
     65         WELL_KNOWN_MIME_TYPES.put(0x15, "application/vnd.wap.wmlscriptc");
     66         WELL_KNOWN_MIME_TYPES.put(0x16, "application/vnd.wap.wta-eventc");
     67         WELL_KNOWN_MIME_TYPES.put(0x17, "application/vnd.wap.uaprof");
     68         WELL_KNOWN_MIME_TYPES.put(0x18, "application/vnd.wap.wtls-ca-certificate");
     69         WELL_KNOWN_MIME_TYPES.put(0x19, "application/vnd.wap.wtls-user-certificate");
     70         WELL_KNOWN_MIME_TYPES.put(0x1A, "application/x-x509-ca-cert");
     71         WELL_KNOWN_MIME_TYPES.put(0x1B, "application/x-x509-user-cert");
     72         WELL_KNOWN_MIME_TYPES.put(0x1C, "image/*");
     73         WELL_KNOWN_MIME_TYPES.put(0x1D, "image/gif");
     74         WELL_KNOWN_MIME_TYPES.put(0x1E, "image/jpeg");
     75         WELL_KNOWN_MIME_TYPES.put(0x1F, "image/tiff");
     76         WELL_KNOWN_MIME_TYPES.put(0x20, "image/png");
     77         WELL_KNOWN_MIME_TYPES.put(0x21, "image/vnd.wap.wbmp");
     78         WELL_KNOWN_MIME_TYPES.put(0x22, "application/vnd.wap.multipart.*");
     79         WELL_KNOWN_MIME_TYPES.put(0x23, "application/vnd.wap.multipart.mixed");
     80         WELL_KNOWN_MIME_TYPES.put(0x24, "application/vnd.wap.multipart.form-data");
     81         WELL_KNOWN_MIME_TYPES.put(0x25, "application/vnd.wap.multipart.byteranges");
     82         WELL_KNOWN_MIME_TYPES.put(0x26, "application/vnd.wap.multipart.alternative");
     83         WELL_KNOWN_MIME_TYPES.put(0x27, "application/xml");
     84         WELL_KNOWN_MIME_TYPES.put(0x28, "text/xml");
     85         WELL_KNOWN_MIME_TYPES.put(0x29, "application/vnd.wap.wbxml");
     86         WELL_KNOWN_MIME_TYPES.put(0x2A, "application/x-x968-cross-cert");
     87         WELL_KNOWN_MIME_TYPES.put(0x2B, "application/x-x968-ca-cert");
     88         WELL_KNOWN_MIME_TYPES.put(0x2C, "application/x-x968-user-cert");
     89         WELL_KNOWN_MIME_TYPES.put(0x2D, "text/vnd.wap.si");
     90         WELL_KNOWN_MIME_TYPES.put(0x2E, "application/vnd.wap.sic");
     91         WELL_KNOWN_MIME_TYPES.put(0x2F, "text/vnd.wap.sl");
     92         WELL_KNOWN_MIME_TYPES.put(0x30, "application/vnd.wap.slc");
     93         WELL_KNOWN_MIME_TYPES.put(0x31, "text/vnd.wap.co");
     94         WELL_KNOWN_MIME_TYPES.put(0x32, "application/vnd.wap.coc");
     95         WELL_KNOWN_MIME_TYPES.put(0x33, "application/vnd.wap.multipart.related");
     96         WELL_KNOWN_MIME_TYPES.put(0x34, "application/vnd.wap.sia");
     97         WELL_KNOWN_MIME_TYPES.put(0x35, "text/vnd.wap.connectivity-xml");
     98         WELL_KNOWN_MIME_TYPES.put(0x36, "application/vnd.wap.connectivity-wbxml");
     99         WELL_KNOWN_MIME_TYPES.put(0x37, "application/pkcs7-mime");
    100         WELL_KNOWN_MIME_TYPES.put(0x38, "application/vnd.wap.hashed-certificate");
    101         WELL_KNOWN_MIME_TYPES.put(0x39, "application/vnd.wap.signed-certificate");
    102         WELL_KNOWN_MIME_TYPES.put(0x3A, "application/vnd.wap.cert-response");
    103         WELL_KNOWN_MIME_TYPES.put(0x3B, "application/xhtml+xml");
    104         WELL_KNOWN_MIME_TYPES.put(0x3C, "application/wml+xml");
    105         WELL_KNOWN_MIME_TYPES.put(0x3D, "text/css");
    106         WELL_KNOWN_MIME_TYPES.put(0x3E, "application/vnd.wap.mms-message");
    107         WELL_KNOWN_MIME_TYPES.put(0x3F, "application/vnd.wap.rollover-certificate");
    108         WELL_KNOWN_MIME_TYPES.put(0x40, "application/vnd.wap.locc+wbxml");
    109         WELL_KNOWN_MIME_TYPES.put(0x41, "application/vnd.wap.loc+xml");
    110         WELL_KNOWN_MIME_TYPES.put(0x42, "application/vnd.syncml.dm+wbxml");
    111         WELL_KNOWN_MIME_TYPES.put(0x43, "application/vnd.syncml.dm+xml");
    112         WELL_KNOWN_MIME_TYPES.put(0x44, "application/vnd.syncml.notification");
    113         WELL_KNOWN_MIME_TYPES.put(0x45, "application/vnd.wap.xhtml+xml");
    114         WELL_KNOWN_MIME_TYPES.put(0x46, "application/vnd.wv.csp.cir");
    115         WELL_KNOWN_MIME_TYPES.put(0x47, "application/vnd.oma.dd+xml");
    116         WELL_KNOWN_MIME_TYPES.put(0x48, "application/vnd.oma.drm.message");
    117         WELL_KNOWN_MIME_TYPES.put(0x49, "application/vnd.oma.drm.content");
    118         WELL_KNOWN_MIME_TYPES.put(0x4A, "application/vnd.oma.drm.rights+xml");
    119         WELL_KNOWN_MIME_TYPES.put(0x4B, "application/vnd.oma.drm.rights+wbxml");
    120         WELL_KNOWN_MIME_TYPES.put(0x4C, "application/vnd.wv.csp+xml");
    121         WELL_KNOWN_MIME_TYPES.put(0x4D, "application/vnd.wv.csp+wbxml");
    122         WELL_KNOWN_MIME_TYPES.put(0x4E, "application/vnd.syncml.ds.notification");
    123         WELL_KNOWN_MIME_TYPES.put(0x4F, "audio/*");
    124         WELL_KNOWN_MIME_TYPES.put(0x50, "video/*");
    125         WELL_KNOWN_MIME_TYPES.put(0x51, "application/vnd.oma.dd2+xml");
    126         WELL_KNOWN_MIME_TYPES.put(0x52, "application/mikey");
    127         WELL_KNOWN_MIME_TYPES.put(0x53, "application/vnd.oma.dcd");
    128         WELL_KNOWN_MIME_TYPES.put(0x54, "application/vnd.oma.dcdc");
    129 
    130         WELL_KNOWN_MIME_TYPES.put(0x0201, "application/vnd.uplanet.cacheop-wbxml");
    131         WELL_KNOWN_MIME_TYPES.put(0x0202, "application/vnd.uplanet.signal");
    132         WELL_KNOWN_MIME_TYPES.put(0x0203, "application/vnd.uplanet.alert-wbxml");
    133         WELL_KNOWN_MIME_TYPES.put(0x0204, "application/vnd.uplanet.list-wbxml");
    134         WELL_KNOWN_MIME_TYPES.put(0x0205, "application/vnd.uplanet.listcmd-wbxml");
    135         WELL_KNOWN_MIME_TYPES.put(0x0206, "application/vnd.uplanet.channel-wbxml");
    136         WELL_KNOWN_MIME_TYPES.put(0x0207, "application/vnd.uplanet.provisioning-status-uri");
    137         WELL_KNOWN_MIME_TYPES.put(0x0208, "x-wap.multipart/vnd.uplanet.header-set");
    138         WELL_KNOWN_MIME_TYPES.put(0x0209, "application/vnd.uplanet.bearer-choice-wbxml");
    139         WELL_KNOWN_MIME_TYPES.put(0x020A, "application/vnd.phonecom.mmc-wbxml");
    140         WELL_KNOWN_MIME_TYPES.put(0x020B, "application/vnd.nokia.syncset+wbxml");
    141         WELL_KNOWN_MIME_TYPES.put(0x020C, "image/x-up-wpng");
    142         WELL_KNOWN_MIME_TYPES.put(0x0300, "application/iota.mmc-wbxml");
    143         WELL_KNOWN_MIME_TYPES.put(0x0301, "application/iota.mmc-xml");
    144         WELL_KNOWN_MIME_TYPES.put(0x0302, "application/vnd.syncml+xml");
    145         WELL_KNOWN_MIME_TYPES.put(0x0303, "application/vnd.syncml+wbxml");
    146         WELL_KNOWN_MIME_TYPES.put(0x0304, "text/vnd.wap.emn+xml");
    147         WELL_KNOWN_MIME_TYPES.put(0x0305, "text/calendar");
    148         WELL_KNOWN_MIME_TYPES.put(0x0306, "application/vnd.omads-email+xml");
    149         WELL_KNOWN_MIME_TYPES.put(0x0307, "application/vnd.omads-file+xml");
    150         WELL_KNOWN_MIME_TYPES.put(0x0308, "application/vnd.omads-folder+xml");
    151         WELL_KNOWN_MIME_TYPES.put(0x0309, "text/directory;profile=vCard");
    152         WELL_KNOWN_MIME_TYPES.put(0x030A, "application/vnd.wap.emn+wbxml");
    153         WELL_KNOWN_MIME_TYPES.put(0x030B, "application/vnd.nokia.ipdc-purchase-response");
    154         WELL_KNOWN_MIME_TYPES.put(0x030C, "application/vnd.motorola.screen3+xml");
    155         WELL_KNOWN_MIME_TYPES.put(0x030D, "application/vnd.motorola.screen3+gzip");
    156         WELL_KNOWN_MIME_TYPES.put(0x030E, "application/vnd.cmcc.setting+wbxml");
    157         WELL_KNOWN_MIME_TYPES.put(0x030F, "application/vnd.cmcc.bombing+wbxml");
    158         WELL_KNOWN_MIME_TYPES.put(0x0310, "application/vnd.docomo.pf");
    159         WELL_KNOWN_MIME_TYPES.put(0x0311, "application/vnd.docomo.ub");
    160         WELL_KNOWN_MIME_TYPES.put(0x0312, "application/vnd.omaloc-supl-init");
    161         WELL_KNOWN_MIME_TYPES.put(0x0313, "application/vnd.oma.group-usage-list+xml");
    162         WELL_KNOWN_MIME_TYPES.put(0x0314, "application/oma-directory+xml");
    163         WELL_KNOWN_MIME_TYPES.put(0x0315, "application/vnd.docomo.pf2");
    164         WELL_KNOWN_MIME_TYPES.put(0x0316, "application/vnd.oma.drm.roap-trigger+wbxml");
    165         WELL_KNOWN_MIME_TYPES.put(0x0317, "application/vnd.sbm.mid2");
    166         WELL_KNOWN_MIME_TYPES.put(0x0318, "application/vnd.wmf.bootstrap");
    167         WELL_KNOWN_MIME_TYPES.put(0x0319, "application/vnc.cmcc.dcd+xml");
    168         WELL_KNOWN_MIME_TYPES.put(0x031A, "application/vnd.sbm.cid");
    169         WELL_KNOWN_MIME_TYPES.put(0x031B, "application/vnd.oma.bcast.provisioningtrigger");
    170 
    171         WELL_KNOWN_PARAMETERS.put(0x00, "Q");
    172         WELL_KNOWN_PARAMETERS.put(0x01, "Charset");
    173         WELL_KNOWN_PARAMETERS.put(0x02, "Level");
    174         WELL_KNOWN_PARAMETERS.put(0x03, "Type");
    175         WELL_KNOWN_PARAMETERS.put(0x07, "Differences");
    176         WELL_KNOWN_PARAMETERS.put(0x08, "Padding");
    177         WELL_KNOWN_PARAMETERS.put(0x09, "Type");
    178         WELL_KNOWN_PARAMETERS.put(0x0E, "Max-Age");
    179         WELL_KNOWN_PARAMETERS.put(0x10, "Secure");
    180         WELL_KNOWN_PARAMETERS.put(0x11, "SEC");
    181         WELL_KNOWN_PARAMETERS.put(0x12, "MAC");
    182         WELL_KNOWN_PARAMETERS.put(0x13, "Creation-date");
    183         WELL_KNOWN_PARAMETERS.put(0x14, "Modification-date");
    184         WELL_KNOWN_PARAMETERS.put(0x15, "Read-date");
    185         WELL_KNOWN_PARAMETERS.put(0x16, "Size");
    186         WELL_KNOWN_PARAMETERS.put(0x17, "Name");
    187         WELL_KNOWN_PARAMETERS.put(0x18, "Filename");
    188         WELL_KNOWN_PARAMETERS.put(0x19, "Start");
    189         WELL_KNOWN_PARAMETERS.put(0x1A, "Start-info");
    190         WELL_KNOWN_PARAMETERS.put(0x1B, "Comment");
    191         WELL_KNOWN_PARAMETERS.put(0x1C, "Domain");
    192         WELL_KNOWN_PARAMETERS.put(0x1D, "Path");
    193     }
    194 
    195     public static final String CONTENT_TYPE_B_PUSH_CO = "application/vnd.wap.coc";
    196     public static final String CONTENT_TYPE_B_MMS = "application/vnd.wap.mms-message";
    197     public static final String CONTENT_TYPE_B_PUSH_SYNCML_NOTI = "application/vnd.syncml.notification";
    198 
    199     byte[] mWspData;
    200     int    mDataLength;
    201     long   mUnsigned32bit;
    202     String mStringValue;
    203 
    204     HashMap<String, String> mContentParameters;
    205 
    206     public WspTypeDecoder(byte[] pdu) {
    207         mWspData = pdu;
    208     }
    209 
    210     /**
    211      * Decode the "Text-string" type for WSP pdu
    212      *
    213      * @param startIndex The starting position of the "Text-string" in this pdu
    214      *
    215      * @return false when error(not a Text-string) occur
    216      *         return value can be retrieved by getValueString() method length of data in pdu can be
    217      *         retrieved by getDecodedDataLength() method
    218      */
    219     public boolean decodeTextString(int startIndex) {
    220         int index = startIndex;
    221         while (mWspData[index] != 0) {
    222             index++;
    223         }
    224         mDataLength = index - startIndex + 1;
    225         if (mWspData[startIndex] == 127) {
    226             mStringValue = new String(mWspData, startIndex + 1, mDataLength - 2);
    227         } else {
    228             mStringValue = new String(mWspData, startIndex, mDataLength - 1);
    229         }
    230         return true;
    231     }
    232 
    233     /**
    234      * Decode the "Token-text" type for WSP pdu
    235      *
    236      * @param startIndex The starting position of the "Token-text" in this pdu
    237      *
    238      * @return always true
    239      *         return value can be retrieved by getValueString() method
    240      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    241      */
    242     public boolean decodeTokenText(int startIndex) {
    243         int index = startIndex;
    244         while (mWspData[index] != 0) {
    245             index++;
    246         }
    247         mDataLength = index - startIndex + 1;
    248         mStringValue = new String(mWspData, startIndex, mDataLength - 1);
    249 
    250         return true;
    251     }
    252 
    253     /**
    254      * Decode the "Short-integer" type for WSP pdu
    255      *
    256      * @param startIndex The starting position of the "Short-integer" in this pdu
    257      *
    258      * @return false when error(not a Short-integer) occur
    259      *         return value can be retrieved by getValue32() method
    260      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    261      */
    262     public boolean decodeShortInteger(int startIndex) {
    263         if ((mWspData[startIndex] & 0x80) == 0) {
    264             return false;
    265         }
    266         mUnsigned32bit = mWspData[startIndex] & 0x7f;
    267         mDataLength = 1;
    268         return true;
    269     }
    270 
    271     /**
    272      * Decode the "Long-integer" type for WSP pdu
    273      *
    274      * @param startIndex The starting position of the "Long-integer" in this pdu
    275      *
    276      * @return false when error(not a Long-integer) occur
    277      *         return value can be retrieved by getValue32() method
    278      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    279      */
    280     public boolean decodeLongInteger(int startIndex) {
    281         int lengthMultiOctet = mWspData[startIndex] & 0xff;
    282 
    283         if (lengthMultiOctet > WAP_PDU_SHORT_LENGTH_MAX) {
    284             return false;
    285         }
    286         mUnsigned32bit = 0;
    287         for (int i = 1; i <= lengthMultiOctet; i++) {
    288             mUnsigned32bit = (mUnsigned32bit << 8) | (mWspData[startIndex + i] & 0xff);
    289         }
    290         mDataLength = 1 + lengthMultiOctet;
    291         return true;
    292     }
    293 
    294     /**
    295      * Decode the "Integer-Value" type for WSP pdu
    296      *
    297      * @param startIndex The starting position of the "Integer-Value" in this pdu
    298      *
    299      * @return false when error(not a Integer-Value) occur
    300      *         return value can be retrieved by getValue32() method
    301      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    302      */
    303     public boolean decodeIntegerValue(int startIndex) {
    304         if (decodeShortInteger(startIndex) == true) {
    305             return true;
    306         }
    307         return decodeLongInteger(startIndex);
    308     }
    309 
    310     /**
    311      * Decode the "Uintvar-integer" type for WSP pdu
    312      *
    313      * @param startIndex The starting position of the "Uintvar-integer" in this pdu
    314      *
    315      * @return false when error(not a Uintvar-integer) occur
    316      *         return value can be retrieved by getValue32() method
    317      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    318      */
    319     public boolean decodeUintvarInteger(int startIndex) {
    320         int index = startIndex;
    321 
    322         mUnsigned32bit = 0;
    323         while ((mWspData[index] & 0x80) != 0) {
    324             if ((index - startIndex) >= 4) {
    325                 return false;
    326             }
    327             mUnsigned32bit = (mUnsigned32bit << 7) | (mWspData[index] & 0x7f);
    328             index++;
    329         }
    330         mUnsigned32bit = (mUnsigned32bit << 7) | (mWspData[index] & 0x7f);
    331         mDataLength = index - startIndex + 1;
    332         return true;
    333     }
    334 
    335     /**
    336      * Decode the "Value-length" type for WSP pdu
    337      *
    338      * @param startIndex The starting position of the "Value-length" in this pdu
    339      *
    340      * @return false when error(not a Value-length) occur
    341      *         return value can be retrieved by getValue32() method
    342      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    343      */
    344     public boolean decodeValueLength(int startIndex) {
    345         if ((mWspData[startIndex] & 0xff) > WAP_PDU_LENGTH_QUOTE) {
    346             return false;
    347         }
    348         if (mWspData[startIndex] < WAP_PDU_LENGTH_QUOTE) {
    349             mUnsigned32bit = mWspData[startIndex];
    350             mDataLength = 1;
    351         } else {
    352             decodeUintvarInteger(startIndex + 1);
    353             mDataLength++;
    354         }
    355         return true;
    356     }
    357 
    358     /**
    359      * Decode the "Extension-media" type for WSP PDU.
    360      *
    361      * @param startIndex The starting position of the "Extension-media" in this PDU.
    362      *
    363      * @return false on error, such as if there is no Extension-media at startIndex.
    364      *         Side-effects: updates stringValue (available with
    365      *         getValueString()), which will be null on error. The length of the
    366      *         data in the PDU is available with getValue32(), 0 on error.
    367      */
    368     public boolean decodeExtensionMedia(int startIndex) {
    369         int index = startIndex;
    370         mDataLength = 0;
    371         mStringValue = null;
    372         int length = mWspData.length;
    373         boolean rtrn = index < length;
    374 
    375         while (index < length && mWspData[index] != 0) {
    376             index++;
    377         }
    378 
    379         mDataLength = index - startIndex + 1;
    380         mStringValue = new String(mWspData, startIndex, mDataLength - 1);
    381 
    382         return rtrn;
    383     }
    384 
    385     /**
    386      * Decode the "Constrained-encoding" type for WSP pdu
    387      *
    388      * @param startIndex The starting position of the "Constrained-encoding" in this pdu
    389      *
    390      * @return false when error(not a Constrained-encoding) occur
    391      *         return value can be retrieved first by getValueString() and second by getValue32() method
    392      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    393      */
    394     public boolean decodeConstrainedEncoding(int startIndex) {
    395         if (decodeShortInteger(startIndex) == true) {
    396             mStringValue = null;
    397             return true;
    398         }
    399         return decodeExtensionMedia(startIndex);
    400     }
    401 
    402     /**
    403      * Decode the "Content-type" type for WSP pdu
    404      *
    405      * @param startIndex The starting position of the "Content-type" in this pdu
    406      *
    407      * @return false when error(not a Content-type) occurs
    408      *         If a content type exists in the headers (either as inline string, or as well-known
    409      *         value), getValueString() will return it. If a 'well known value' is encountered that
    410      *         cannot be mapped to a string mime type, getValueString() will return null, and
    411      *         getValue32() will return the unknown content type value.
    412      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    413      *         Any content type parameters will be accessible via getContentParameters()
    414      */
    415     public boolean decodeContentType(int startIndex) {
    416         int mediaPrefixLength;
    417         mContentParameters = new HashMap<String, String>();
    418 
    419         try {
    420             if (decodeValueLength(startIndex) == false) {
    421                 boolean found = decodeConstrainedEncoding(startIndex);
    422                 if (found) {
    423                     expandWellKnownMimeType();
    424                 }
    425                 return found;
    426             }
    427             int headersLength = (int) mUnsigned32bit;
    428             mediaPrefixLength = getDecodedDataLength();
    429             if (decodeIntegerValue(startIndex + mediaPrefixLength) == true) {
    430                 mDataLength += mediaPrefixLength;
    431                 int readLength = mDataLength;
    432                 mStringValue = null;
    433                 expandWellKnownMimeType();
    434                 long wellKnownValue = mUnsigned32bit;
    435                 String mimeType = mStringValue;
    436                 if (readContentParameters(startIndex + mDataLength,
    437                         (headersLength - (mDataLength - mediaPrefixLength)), 0)) {
    438                     mDataLength += readLength;
    439                     mUnsigned32bit = wellKnownValue;
    440                     mStringValue = mimeType;
    441                     return true;
    442                 }
    443                 return false;
    444             }
    445             if (decodeExtensionMedia(startIndex + mediaPrefixLength) == true) {
    446                 mDataLength += mediaPrefixLength;
    447                 int readLength = mDataLength;
    448                 expandWellKnownMimeType();
    449                 long wellKnownValue = mUnsigned32bit;
    450                 String mimeType = mStringValue;
    451                 if (readContentParameters(startIndex + mDataLength,
    452                         (headersLength - (mDataLength - mediaPrefixLength)), 0)) {
    453                     mDataLength += readLength;
    454                     mUnsigned32bit = wellKnownValue;
    455                     mStringValue = mimeType;
    456                     return true;
    457                 }
    458             }
    459         } catch (ArrayIndexOutOfBoundsException e) {
    460             //something doesn't add up
    461             return false;
    462         }
    463         return false;
    464     }
    465 
    466     private boolean readContentParameters(int startIndex, int leftToRead, int accumulator) {
    467 
    468         int totalRead = 0;
    469 
    470         if (leftToRead > 0) {
    471             byte nextByte = mWspData[startIndex];
    472             String value = null;
    473             String param = null;
    474             if ((nextByte & 0x80) == 0x00 && nextByte > 31) { // untyped
    475                 decodeTokenText(startIndex);
    476                 param = mStringValue;
    477                 totalRead += mDataLength;
    478             } else { // typed
    479                 if (decodeIntegerValue(startIndex)) {
    480                     totalRead += mDataLength;
    481                     int wellKnownParameterValue = (int) mUnsigned32bit;
    482                     param = WELL_KNOWN_PARAMETERS.get(wellKnownParameterValue);
    483                     if (param == null) {
    484                         param = "unassigned/0x" + Long.toHexString(wellKnownParameterValue);
    485                     }
    486                     // special case for the "Q" parameter, value is a uintvar
    487                     if (wellKnownParameterValue == Q_VALUE) {
    488                         if (decodeUintvarInteger(startIndex + totalRead)) {
    489                             totalRead += mDataLength;
    490                             value = String.valueOf(mUnsigned32bit);
    491                             mContentParameters.put(param, value);
    492                             return readContentParameters(startIndex + totalRead, leftToRead
    493                                                             - totalRead, accumulator + totalRead);
    494                         } else {
    495                             return false;
    496                         }
    497                     }
    498                 } else {
    499                     return false;
    500                 }
    501             }
    502 
    503             if (decodeNoValue(startIndex + totalRead)) {
    504                 totalRead += mDataLength;
    505                 value = null;
    506             } else if (decodeIntegerValue(startIndex + totalRead)) {
    507                 totalRead += mDataLength;
    508                 int intValue = (int) mUnsigned32bit;
    509                 value = String.valueOf(intValue);
    510             } else {
    511                 decodeTokenText(startIndex + totalRead);
    512                 totalRead += mDataLength;
    513                 value = mStringValue;
    514                 if (value.startsWith("\"")) {
    515                     // quoted string, so remove the quote
    516                     value = value.substring(1);
    517                 }
    518             }
    519             mContentParameters.put(param, value);
    520             return readContentParameters(startIndex + totalRead, leftToRead - totalRead,
    521                                             accumulator + totalRead);
    522 
    523         } else {
    524             mDataLength = accumulator;
    525             return true;
    526         }
    527     }
    528 
    529     /**
    530      * Check if the next byte is No-Value
    531      *
    532      * @param startIndex The starting position of the "Content length" in this pdu
    533      *
    534      * @return true if and only if the next byte is 0x00
    535      */
    536     private boolean decodeNoValue(int startIndex) {
    537         if (mWspData[startIndex] == 0) {
    538             mDataLength = 1;
    539             return true;
    540         } else {
    541             return false;
    542         }
    543     }
    544 
    545     /**
    546      * Populate stringValue with the mime type corresponding to the value in unsigned32bit
    547      *
    548      * Sets unsigned32bit to -1 if stringValue is already populated
    549      */
    550     private void expandWellKnownMimeType() {
    551         if (mStringValue == null) {
    552             int binaryContentType = (int) mUnsigned32bit;
    553             mStringValue = WELL_KNOWN_MIME_TYPES.get(binaryContentType);
    554         } else {
    555             mUnsigned32bit = -1;
    556         }
    557     }
    558 
    559     /**
    560      * Decode the "Content length" type for WSP pdu
    561      *
    562      * @param startIndex The starting position of the "Content length" in this pdu
    563      *
    564      * @return false when error(not a Content length) occur
    565      *         return value can be retrieved by getValue32() method
    566      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    567      */
    568     public boolean decodeContentLength(int startIndex) {
    569         return decodeIntegerValue(startIndex);
    570     }
    571 
    572     /**
    573      * Decode the "Content location" type for WSP pdu
    574      *
    575      * @param startIndex The starting position of the "Content location" in this pdu
    576      *
    577      * @return false when error(not a Content location) occur
    578      *         return value can be retrieved by getValueString() method
    579      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    580      */
    581     public boolean decodeContentLocation(int startIndex) {
    582         return decodeTextString(startIndex);
    583     }
    584 
    585     /**
    586      * Decode the "X-Wap-Application-Id" type for WSP pdu
    587      *
    588      * @param startIndex The starting position of the "X-Wap-Application-Id" in this pdu
    589      *
    590      * @return false when error(not a X-Wap-Application-Id) occur
    591      *         return value can be retrieved first by getValueString() and second by getValue32()
    592      *         method
    593      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    594      */
    595     public boolean decodeXWapApplicationId(int startIndex) {
    596         if (decodeIntegerValue(startIndex) == true) {
    597             mStringValue = null;
    598             return true;
    599         }
    600         return decodeTextString(startIndex);
    601     }
    602 
    603     /**
    604      * Seek for the "X-Wap-Application-Id" field for WSP pdu
    605      *
    606      * @param startIndex The starting position of seek pointer
    607      * @param endIndex Valid seek area end point
    608      *
    609      * @return false when error(not a X-Wap-Application-Id) occur
    610      *         return value can be retrieved by getValue32()
    611      */
    612     public boolean seekXWapApplicationId(int startIndex, int endIndex) {
    613         int index = startIndex;
    614 
    615         try {
    616             for (index = startIndex; index <= endIndex; ) {
    617                 /**
    618                  * 8.4.1.1  Field name
    619                  * Field name is integer or text.
    620                  */
    621                 if (decodeIntegerValue(index)) {
    622                     int fieldValue = (int) getValue32();
    623 
    624                     if (fieldValue == PARAMETER_ID_X_WAP_APPLICATION_ID) {
    625                         mUnsigned32bit = index + 1;
    626                         return true;
    627                     }
    628                 } else {
    629                     if (!decodeTextString(index)) return false;
    630                 }
    631                 index += getDecodedDataLength();
    632                 if (index > endIndex) return false;
    633 
    634                 /**
    635                  * 8.4.1.2 Field values
    636                  * Value Interpretation of First Octet
    637                  * 0 - 30 This octet is followed by the indicated number (0 - 30)
    638                         of data octets
    639                  * 31 This octet is followed by a uintvar, which indicates the number
    640                  *      of data octets after it
    641                  * 32 - 127 The value is a text string, terminated by a zero octet
    642                         (NUL character)
    643                  * 128 - 255 It is an encoded 7-bit value; this header has no more data
    644                  */
    645                 byte val = mWspData[index];
    646                 if (0 <= val && val <= WAP_PDU_SHORT_LENGTH_MAX) {
    647                     index += mWspData[index] + 1;
    648                 } else if (val == WAP_PDU_LENGTH_QUOTE) {
    649                     if (index + 1 >= endIndex) return false;
    650                     index++;
    651                     if (!decodeUintvarInteger(index)) return false;
    652                     index += getDecodedDataLength();
    653                 } else if (WAP_PDU_LENGTH_QUOTE < val && val <= 127) {
    654                     if (!decodeTextString(index)) return false;
    655                     index += getDecodedDataLength();
    656                 } else {
    657                     index++;
    658                 }
    659             }
    660         } catch (ArrayIndexOutOfBoundsException e) {
    661             //seek application ID failed. WSP header might be corrupted
    662             return false;
    663         }
    664         return false;
    665     }
    666 
    667     /**
    668      * Decode the "X-Wap-Content-URI" type for WSP pdu
    669      *
    670      * @param startIndex The starting position of the "X-Wap-Content-URI" in this pdu
    671      *
    672      * @return false when error(not a X-Wap-Content-URI) occur
    673      *         return value can be retrieved by getValueString() method
    674      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    675      */
    676     public boolean decodeXWapContentURI(int startIndex) {
    677         return decodeTextString(startIndex);
    678     }
    679 
    680     /**
    681      * Decode the "X-Wap-Initiator-URI" type for WSP pdu
    682      *
    683      * @param startIndex The starting position of the "X-Wap-Initiator-URI" in this pdu
    684      *
    685      * @return false when error(not a X-Wap-Initiator-URI) occur
    686      *         return value can be retrieved by getValueString() method
    687      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    688      */
    689     public boolean decodeXWapInitiatorURI(int startIndex) {
    690         return decodeTextString(startIndex);
    691     }
    692 
    693     /**
    694      * The data length of latest operation.
    695      */
    696     public int getDecodedDataLength() {
    697         return mDataLength;
    698     }
    699 
    700     /**
    701      * The 32-bits result of latest operation.
    702      */
    703     public long getValue32() {
    704         return mUnsigned32bit;
    705     }
    706 
    707     /**
    708      * The String result of latest operation.
    709      */
    710     public String getValueString() {
    711         return mStringValue;
    712     }
    713 
    714     /**
    715      * Any parameters encountered as part of a decodeContentType() invocation.
    716      *
    717      * @return a map of content parameters keyed by their names, or null if
    718      *         decodeContentType() has not been called If any unassigned
    719      *         well-known parameters are encountered, the key of the map will be
    720      *         'unassigned/0x...', where '...' is the hex value of the
    721      *         unassigned parameter.  If a parameter has No-Value the value will be null.
    722      *
    723      */
    724     public HashMap<String, String> getContentParameters() {
    725         return mContentParameters;
    726     }
    727 }
    728