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