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