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[] wspData;
    200     int    dataLength;
    201     long   unsigned32bit;
    202     String stringValue;
    203 
    204     HashMap<String, String> contentParameters;
    205 
    206     public WspTypeDecoder(byte[] pdu) {
    207         wspData = 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 (wspData[index] != 0) {
    222             index++;
    223         }
    224         dataLength = index - startIndex + 1;
    225         if (wspData[startIndex] == 127) {
    226             stringValue = new String(wspData, startIndex + 1, dataLength - 2);
    227         } else {
    228             stringValue = new String(wspData, startIndex, dataLength - 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 (wspData[index] != 0) {
    245             index++;
    246         }
    247         dataLength = index - startIndex + 1;
    248         stringValue = new String(wspData, startIndex, dataLength - 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 ((wspData[startIndex] & 0x80) == 0) {
    264             return false;
    265         }
    266         unsigned32bit = wspData[startIndex] & 0x7f;
    267         dataLength = 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 = wspData[startIndex] & 0xff;
    282 
    283         if (lengthMultiOctet > WAP_PDU_SHORT_LENGTH_MAX) {
    284             return false;
    285         }
    286         unsigned32bit = 0;
    287         for (int i = 1; i <= lengthMultiOctet; i++) {
    288             unsigned32bit = (unsigned32bit << 8) | (wspData[startIndex + i] & 0xff);
    289         }
    290         dataLength = 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         unsigned32bit = 0;
    323         while ((wspData[index] & 0x80) != 0) {
    324             if ((index - startIndex) >= 4) {
    325                 return false;
    326             }
    327             unsigned32bit = (unsigned32bit << 7) | (wspData[index] & 0x7f);
    328             index++;
    329         }
    330         unsigned32bit = (unsigned32bit << 7) | (wspData[index] & 0x7f);
    331         dataLength = 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 ((wspData[startIndex] & 0xff) > WAP_PDU_LENGTH_QUOTE) {
    346             return false;
    347         }
    348         if (wspData[startIndex] < WAP_PDU_LENGTH_QUOTE) {
    349             unsigned32bit = wspData[startIndex];
    350             dataLength = 1;
    351         } else {
    352             decodeUintvarInteger(startIndex + 1);
    353             dataLength++;
    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         dataLength = 0;
    371         stringValue = null;
    372         int length = wspData.length;
    373         boolean rtrn = index < length;
    374 
    375         while (index < length && wspData[index] != 0) {
    376             index++;
    377         }
    378 
    379         dataLength = index - startIndex + 1;
    380         stringValue = new String(wspData, startIndex, dataLength - 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             stringValue = 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         contentParameters = 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) unsigned32bit;
    428             mediaPrefixLength = getDecodedDataLength();
    429             if (decodeIntegerValue(startIndex + mediaPrefixLength) == true) {
    430                 dataLength += mediaPrefixLength;
    431                 int readLength = dataLength;
    432                 stringValue = null;
    433                 expandWellKnownMimeType();
    434                 long wellKnownValue = unsigned32bit;
    435                 String mimeType = stringValue;
    436                 if (readContentParameters(startIndex + dataLength,
    437                         (headersLength - (dataLength - mediaPrefixLength)), 0)) {
    438                     dataLength += readLength;
    439                     unsigned32bit = wellKnownValue;
    440                     stringValue = mimeType;
    441                     return true;
    442                 }
    443                 return false;
    444             }
    445             if (decodeExtensionMedia(startIndex + mediaPrefixLength) == true) {
    446                 dataLength += mediaPrefixLength;
    447                 int readLength = dataLength;
    448                 expandWellKnownMimeType();
    449                 long wellKnownValue = unsigned32bit;
    450                 String mimeType = stringValue;
    451                 if (readContentParameters(startIndex + dataLength,
    452                         (headersLength - (dataLength - mediaPrefixLength)), 0)) {
    453                     dataLength += readLength;
    454                     unsigned32bit = wellKnownValue;
    455                     stringValue = 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 = wspData[startIndex];
    472             String value = null;
    473             String param = null;
    474             if ((nextByte & 0x80) == 0x00 && nextByte > 31) { // untyped
    475                 decodeTokenText(startIndex);
    476                 param = stringValue;
    477                 totalRead += dataLength;
    478             } else { // typed
    479                 if (decodeIntegerValue(startIndex)) {
    480                     totalRead += dataLength;
    481                     int wellKnownParameterValue = (int) unsigned32bit;
    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 += dataLength;
    490                             value = String.valueOf(unsigned32bit);
    491                             contentParameters.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 += dataLength;
    505                 value = null;
    506             } else if (decodeIntegerValue(startIndex + totalRead)) {
    507                 totalRead += dataLength;
    508                 int intValue = (int) unsigned32bit;
    509                 if (intValue == 0) {
    510                     value = "";
    511                 } else {
    512                     value = String.valueOf(intValue);
    513                 }
    514             } else {
    515                 decodeTokenText(startIndex + totalRead);
    516                 totalRead += dataLength;
    517                 value = stringValue;
    518                 if (value.startsWith("\"")) {
    519                     // quoted string, so remove the quote
    520                     value = value.substring(1);
    521                 }
    522             }
    523             contentParameters.put(param, value);
    524             return readContentParameters(startIndex + totalRead, leftToRead - totalRead,
    525                                             accumulator + totalRead);
    526 
    527         } else {
    528             dataLength = accumulator;
    529             return true;
    530         }
    531     }
    532 
    533     /**
    534      * Check if the next byte is No-Value
    535      *
    536      * @param startIndex The starting position of the "Content length" in this pdu
    537      *
    538      * @return true if and only if the next byte is 0x00
    539      */
    540     private boolean decodeNoValue(int startIndex) {
    541         if (wspData[startIndex] == 0) {
    542             dataLength = 1;
    543             return true;
    544         } else {
    545             return false;
    546         }
    547     }
    548 
    549     /**
    550      * Populate stringValue with the mime type corresponding to the value in unsigned32bit
    551      *
    552      * Sets unsigned32bit to -1 if stringValue is already populated
    553      */
    554     private void expandWellKnownMimeType() {
    555         if (stringValue == null) {
    556             int binaryContentType = (int) unsigned32bit;
    557             stringValue = WELL_KNOWN_MIME_TYPES.get(binaryContentType);
    558         } else {
    559             unsigned32bit = -1;
    560         }
    561     }
    562 
    563     /**
    564      * Decode the "Content length" type for WSP pdu
    565      *
    566      * @param startIndex The starting position of the "Content length" in this pdu
    567      *
    568      * @return false when error(not a Content length) occur
    569      *         return value can be retrieved by getValue32() method
    570      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    571      */
    572     public boolean decodeContentLength(int startIndex) {
    573         return decodeIntegerValue(startIndex);
    574     }
    575 
    576     /**
    577      * Decode the "Content location" type for WSP pdu
    578      *
    579      * @param startIndex The starting position of the "Content location" in this pdu
    580      *
    581      * @return false when error(not a Content location) occur
    582      *         return value can be retrieved by getValueString() method
    583      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    584      */
    585     public boolean decodeContentLocation(int startIndex) {
    586         return decodeTextString(startIndex);
    587     }
    588 
    589     /**
    590      * Decode the "X-Wap-Application-Id" type for WSP pdu
    591      *
    592      * @param startIndex The starting position of the "X-Wap-Application-Id" in this pdu
    593      *
    594      * @return false when error(not a X-Wap-Application-Id) occur
    595      *         return value can be retrieved first by getValueString() and second by getValue32()
    596      *         method
    597      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    598      */
    599     public boolean decodeXWapApplicationId(int startIndex) {
    600         if (decodeIntegerValue(startIndex) == true) {
    601             stringValue = null;
    602             return true;
    603         }
    604         return decodeTextString(startIndex);
    605     }
    606 
    607     /**
    608      * Seek for the "X-Wap-Application-Id" field for WSP pdu
    609      *
    610      * @param startIndex The starting position of seek pointer
    611      * @param endIndex Valid seek area end point
    612      *
    613      * @return false when error(not a X-Wap-Application-Id) occur
    614      *         return value can be retrieved by getValue32()
    615      */
    616     public boolean seekXWapApplicationId(int startIndex, int endIndex) {
    617         int index = startIndex;
    618 
    619         try {
    620             for (index = startIndex; index <= endIndex; ) {
    621                 /**
    622                  * 8.4.1.1  Field name
    623                  * Field name is integer or text.
    624                  */
    625                 if (decodeIntegerValue(index)) {
    626                     int fieldValue = (int) getValue32();
    627 
    628                     if (fieldValue == PARAMETER_ID_X_WAP_APPLICATION_ID) {
    629                         unsigned32bit = index + 1;
    630                         return true;
    631                     }
    632                 } else {
    633                     if (!decodeTextString(index)) return false;
    634                 }
    635                 index += getDecodedDataLength();
    636                 if (index > endIndex) return false;
    637 
    638                 /**
    639                  * 8.4.1.2 Field values
    640                  * Value Interpretation of First Octet
    641                  * 0 - 30 This octet is followed by the indicated number (0 - 30)
    642                         of data octets
    643                  * 31 This octet is followed by a uintvar, which indicates the number
    644                  *      of data octets after it
    645                  * 32 - 127 The value is a text string, terminated by a zero octet
    646                         (NUL character)
    647                  * 128 - 255 It is an encoded 7-bit value; this header has no more data
    648                  */
    649                 byte val = wspData[index];
    650                 if (0 <= val && val <= WAP_PDU_SHORT_LENGTH_MAX) {
    651                     index += wspData[index] + 1;
    652                 } else if (val == WAP_PDU_LENGTH_QUOTE) {
    653                     if (index + 1 >= endIndex) return false;
    654                     index++;
    655                     if (!decodeUintvarInteger(index)) return false;
    656                     index += getDecodedDataLength();
    657                 } else if (WAP_PDU_LENGTH_QUOTE < val && val <= 127) {
    658                     if (!decodeTextString(index)) return false;
    659                     index += getDecodedDataLength();
    660                 } else {
    661                     index++;
    662                 }
    663             }
    664         } catch (ArrayIndexOutOfBoundsException e) {
    665             //seek application ID failed. WSP header might be corrupted
    666             return false;
    667         }
    668         return false;
    669     }
    670 
    671     /**
    672      * Decode the "X-Wap-Content-URI" type for WSP pdu
    673      *
    674      * @param startIndex The starting position of the "X-Wap-Content-URI" in this pdu
    675      *
    676      * @return false when error(not a X-Wap-Content-URI) occur
    677      *         return value can be retrieved by getValueString() method
    678      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    679      */
    680     public boolean decodeXWapContentURI(int startIndex) {
    681         return decodeTextString(startIndex);
    682     }
    683 
    684     /**
    685      * Decode the "X-Wap-Initiator-URI" type for WSP pdu
    686      *
    687      * @param startIndex The starting position of the "X-Wap-Initiator-URI" in this pdu
    688      *
    689      * @return false when error(not a X-Wap-Initiator-URI) occur
    690      *         return value can be retrieved by getValueString() method
    691      *         length of data in pdu can be retrieved by getDecodedDataLength() method
    692      */
    693     public boolean decodeXWapInitiatorURI(int startIndex) {
    694         return decodeTextString(startIndex);
    695     }
    696 
    697     /**
    698      * The data length of latest operation.
    699      */
    700     public int getDecodedDataLength() {
    701         return dataLength;
    702     }
    703 
    704     /**
    705      * The 32-bits result of latest operation.
    706      */
    707     public long getValue32() {
    708         return unsigned32bit;
    709     }
    710 
    711     /**
    712      * The String result of latest operation.
    713      */
    714     public String getValueString() {
    715         return stringValue;
    716     }
    717 
    718     /**
    719      * Any parameters encountered as part of a decodeContentType() invocation.
    720      *
    721      * @return a map of content parameters keyed by their names, or null if
    722      *         decodeContentType() has not been called If any unassigned
    723      *         well-known parameters are encountered, the key of the map will be
    724      *         'unassigned/0x...', where '...' is the hex value of the
    725      *         unassigned parameter.  If a parameter has No-Value the value will be null.
    726      *
    727      */
    728     public HashMap<String, String> getContentParameters() {
    729         return contentParameters;
    730     }
    731 }
    732