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