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