blob: fccbfbf4dbebb182751b1c31cc827e6381ebe529 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
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#include <string>
17#include <memory>
18#include <iostream>
19#include <list>
20#include <algorithm>
21using namespace std;
22
23#include "BearerData.h"
24#include "UserData.h"
25#include "SmsConstants.h"
26#include "HexDump.h"
27#include "IccUtils.h"
28#include "BitwiseInputStream.h"
29#include "CdmaSmsCbProgramData.h";
30#include "SmsHeader.h"
31#include "GsmAlphabet.h"
32#include "SmsEnvelope.h"
33
34extern "C" {
35 #include <glib.h>
36}
37
38BearerData::BearerData() {
39 // TODO Auto-generated constructor stub
40
41}
42
43BearerData::~BearerData() {
44 // TODO Auto-generated destructor stub
45}
46
47/**
48 * Decodes a CDMA style BCD byte like {@link #gsmBcdByteToInt}, but
49 * opposite nibble format. The least significant BCD digit
50 * is in the least significant nibble and the most significant
51 * is in the most significant nibble.
52 */
53int BearerData::cdmaBcdByteToInt(uint8_t b) {
54 int ret = 0;
55
56 // treat out-of-range BCD values as 0
57 if ((b & 0xf0) <= 0x90) {
58 ret = ((b >> 4) & 0xf) * 10;
59 }
60
61 if ((b & 0x0f) <= 0x09) {
62 ret += (b & 0xf);
63 }
64
65 return ret;
66}
67
68void BearerData::fromByteArray(std::vector<uint8_t> data, struct tm& ts) {
69 // C.S0015-B v2.0, 4.5.4: range is 1996-2095
70 int year = cdmaBcdByteToInt(data[0]);
71 if (year > 99 || year < 0) {
72 ts = {0};
73 return;
74 }
75 ts.tm_year = year /*>= 96 ? year + 1900 : year + 2000*/; //TBD
76 int month = cdmaBcdByteToInt(data[1]);
77 if (month < 1 || month > 12) {
78 ts = {0};
79 return;
80 }
81 ts.tm_mon = month - 1;
82 int day = cdmaBcdByteToInt(data[2]);
83 if (day < 1 || day > 31) {
84 ts = {0};
85 return;
86 }
87 ts.tm_mday = day;
88 int hour = cdmaBcdByteToInt(data[3]);
89 if (hour < 0 || hour > 23) {
90 ts = {0};
91 return;
92 }
93 ts.tm_hour = hour;
94 int minute = cdmaBcdByteToInt(data[4]);
95 if (minute < 0 || minute > 59) {
96 ts = {0};
97 return;
98 }
99 ts.tm_min = minute;
100 int second = cdmaBcdByteToInt(data[5]);
101 if (second < 0 || second > 59) {
102 ts = {0};
103 return;
104 }
105 ts.tm_sec = second;
106}
107
108void BearerData::encodeMessageId(BearerData* bData,
109 shared_ptr<BitwiseOutputStream> outStream) {
110 outStream->write(8, 3);
111 outStream->write(4, bData->messageType);
112 outStream->write(8, bData->messageId >> 8);
113 outStream->write(8, bData->messageId);
114 outStream->write(1, bData->hasUserDataHeader ? 1 : 0);
115 outStream->skip(3);
116}
117
118uint32_t BearerData::countAsciiSeptets(char* msg, bool force) {
119 string strmsg(msg);
120 int msgLen = strmsg.length();
121 if (force)
122 return msgLen;
123 for (int i = 0; i < msgLen; i++) {
124 if (UserData::charToAscii.find(msg[i]) == UserData::charToAscii.end()) {
125 return -1;
126 }
127 }
128 return msgLen;
129}
130
131std::vector<uint8_t> BearerData::encodeUtf16(std::string msg) {
132 GError *error = NULL;
133 gsize bytes_written = 0;
134 std::vector<uint8_t> data;
135 char *ret = g_convert (msg.c_str(), -1, "UCS-2BE", "UTF-8", NULL, &bytes_written, &error);
136 if (!ret) {
137 if (error) {
138 cout << "failed to convert UTF-8 to UCS-2BE character set: " << (error->code) << error->message << endl;
139 g_error_free (error);
140 }
141 return data;
142 }
143 for (int i = 0; i < bytes_written; i++) {
144 data.push_back(ret[i]);
145 }
146 g_free (ret);
147 return data;
148}
149
150//release byte[]
151std::vector<uint8_t> BearerData::encode7bitAscii(std::string msgs, bool force) {
152 string msg(msgs);
153 shared_ptr<BitwiseOutputStream> outStream = make_shared<BitwiseOutputStream>(
154 msg.length());
155 int msgLen = msg.length();
156 for (int i = 0; i < msgLen; i++) {
157 uint8_t charCode;
158 try {
159 charCode = UserData::charToAscii.at(msg[i]);
160 outStream->write(7, charCode);
161 } catch (const out_of_range &e) {
162 if (force) {
163 outStream->write(7, UserData::UNENCODABLE_7_BIT_CHAR);
164 }
165 //TBD log
166 }
167 }
168 return outStream->toByteVector();
169}
170
171BearerData::Gsm7bitCodingResult BearerData::encode7bitGsm(std::string msg, int septetOffset, bool force) {
172 std::vector<uint8_t> fullData = GsmAlphabet::stringToGsm7BitPacked(msg, septetOffset, !force, 0, 0);
173 Gsm7bitCodingResult result;
174 result.data.insert(result.data.begin(), fullData.begin() + 1, fullData.end());
175 result.septets = fullData[0] & 0x00FF;
176 return result;
177}
178
179void BearerData::encode7bitEms(std::shared_ptr<UserData> uData, std::vector<uint8_t> udhData, bool force) {
180 int udhBytes = udhData.size() + 1; // Add length octet.
181 int udhSeptets = ((udhBytes * 8) + 6) / 7;
182 BearerData::Gsm7bitCodingResult gcr = encode7bitGsm(uData->payloadStr, udhSeptets, force);
183 uData->msgEncoding = UserData::ENCODING_GSM_7BIT_ALPHABET;
184 uData->msgEncodingSet = true;
185 uData->numFields = gcr.septets;
186 uData->payload = gcr.data;
187 uData->payload.insert(uData->payload.begin()+1, udhData.begin(), udhData.end());
188 uData->payload[0] = (uint8_t)udhData.size();
189}
190
191void BearerData::encode16bitEms(std::shared_ptr<UserData> uData, std::vector<uint8_t> udhData) {
192 std::vector<uint8_t> payload = encodeUtf16(uData->payloadStr);
193 int udhBytes = udhData.size() + 1; // Add length octet.
194 int udhCodeUnits = (udhBytes + 1) / 2;
195 int payloadCodeUnits = payload.size() / 2;
196 uData->msgEncoding = UserData::ENCODING_UNICODE_16;
197 uData->msgEncodingSet = true;
198 uData->numFields = udhCodeUnits + payloadCodeUnits;
199 uData->payload.push_back(udhData.size());
200 (uData->payload).insert((uData->payload).begin() + 1, udhData.begin(), udhData.end());
201 (uData->payload).insert((uData->payload).begin() + udhBytes, payload.begin(), payload.end());
202}
203
204void BearerData::encodeOctetEms(std::shared_ptr<UserData> uData, std::vector<uint8_t> udhData) {
205 int udhBytes = udhData.size() + 1;
206 uData->msgEncoding = UserData::ENCODING_OCTET;
207 uData->msgEncodingSet = true;
208 uData->numFields = udhBytes + uData->payload.size();
209 //byte[] payload = new byte[uData.numFields];
210 std::vector<uint8_t> payload;
211 uData->payload.push_back(udhData.size());
212 (uData->payload).insert((uData->payload).begin() + 1, udhData.begin(), udhData.end());
213 (uData->payload).insert((uData->payload).begin() + udhBytes, payload.begin(), payload.end());
214}
215
216void BearerData::encodeEmsUserDataPayload(std::shared_ptr<UserData> uData) {
217 std::vector<uint8_t> headerData = SmsHeader::toByteArray(uData->userDataHeader);
218 if (uData->msgEncodingSet) {
219 if (uData->msgEncoding == UserData::ENCODING_GSM_7BIT_ALPHABET) {
220 encode7bitEms(uData, headerData, true);
221 } else if (uData->msgEncoding == UserData::ENCODING_OCTET) {
222 encodeOctetEms(uData, headerData);
223 } else if (uData->msgEncoding == UserData::ENCODING_UNICODE_16) {
224 encode16bitEms(uData, headerData);
225 } else {
226 cout << "unsupported EMS user data encoding (" << uData->msgEncoding << ")" <<endl;
227 }
228 } else {
229 encode7bitEms(uData, headerData, false);
230 }
231}
232//maybe free memory
233void BearerData::encodeUserDataPayload(std::shared_ptr<UserData> uData) {
234 if ((uData->payloadStr.empty())
235 && (uData->msgEncoding != UserData::ENCODING_OCTET)) {
236 //Rlog.e(LOG_TAG, "user data with null payloadStr");
237 uData->payloadStr = string("");
238 }
239
240 if (uData->userDataHeader != nullptr) {
241 encodeEmsUserDataPayload(uData);
242 return;
243 }
244
245 if (uData->msgEncodingSet) {
246 if (uData->msgEncoding == UserData::ENCODING_OCTET) {
247 if (uData->payload.empty()) {
248 //Rlog.e(LOG_TAG, "user data with octet encoding but null payload");
249 uData->payload.clear();
250 uData->numFields = 0;
251 } else {
252 uData->numFields = uData->payload.size(); //maybe wrong?
253 }
254 } else {
255 if (uData->payloadStr.empty()) {
256 //Rlog.e(LOG_TAG, "non-octet user data with null payloadStr");
257 uData->payloadStr = string("");
258 }
259// if (uData.msgEncoding == UserData::ENCODING_GSM_7BIT_ALPHABET) {
260// Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true);
261// uData.payload = gcr.data;
262// uData.numFields = gcr.septets;
263// } else
264
265 if (uData->msgEncoding == UserData::ENCODING_7BIT_ASCII) {
266 uData->payload = encode7bitAscii(uData->payloadStr, true);
267 uData->numFields = uData->payloadStr.size();
268 } else if (uData->msgEncoding == UserData::ENCODING_UNICODE_16) {
269 uData->payload = encodeUtf16(uData->payloadStr);
270 uData->numFields = string(uData->payloadStr).length();
271// } else if (uData->msgEncoding == UserData::ENCODING_SHIFT_JIS) {
272// uData->payload = encodeShiftJis(uData->payloadStr);
273// uData->numFields = string(uData->payloadStr).length();
274 } else {
275 cout << "unsupported user data encoding (" << uData->msgEncoding << ")"
276 << endl;
277 }
278 }
279 } else {
280 uData->payload = encode7bitAscii(uData->payloadStr, false);
281 string str1 = HexDump::toHexString(uData->payload);
282 //std::cout << "uData->payload: " << str1 << endl;
283 uData->msgEncoding = UserData::ENCODING_7BIT_ASCII;
284// try {
285// } catch (CodingException ex) {
286// uData.payload = encodeUtf16(uData.payloadStr);
287// uData.msgEncoding = UserData.ENCODING_UNICODE_16;
288// }
289 uData->numFields = uData->payloadStr.size();
290 uData->msgEncodingSet = true;
291 }
292}
293
294void BearerData::encodeUserData(BearerData* bData,
295 shared_ptr<BitwiseOutputStream> outStream) {
296 /*
297 * TODO(cleanup): Do we really need to set userData.payload as
298 * a side effect of encoding? If not, we could avoid data
299 * copies by passing outStream directly.
300 */
301 encodeUserDataPayload(bData->userData);
302 bData->hasUserDataHeader = false; //bData->userData->userDataHeader != null;
303
304 int length = bData->userData->payload.size();
305 if (length > SmsConstants::MAX_USER_DATA_BYTES) {
306 cout << "encoded user data too large (" << bData->userData->payload.size()
307 << " > " << SmsConstants::MAX_USER_DATA_BYTES << " bytes)" << endl;
308 return;
309 }
310
311 /*
312 * TODO(cleanup): figure out what the right answer is WRT paddingBits field
313 *
314 * userData->pad->ingBits = (userData->payload.length * 8) - (userData.numFields * 7);
315 * userData.paddingBits = 0; // XXX this seems better, but why?
316 *
317 */
318 int dataBits = (length * 8) - (bData->userData->paddingBits);
319 int paramBits = dataBits + 13;
320 if (((bData->userData->msgEncoding)
321 == UserData::ENCODING_IS91_EXTENDED_PROTOCOL)
322 || ((bData->userData->msgEncoding) == UserData::ENCODING_GSM_DCS)) {
323 paramBits += 8;
324 }
325 int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
326 int paddingBits = (paramBytes * 8) - paramBits;
327 outStream->write(8, paramBytes);
328 outStream->write(5, bData->userData->msgEncoding);
329 if ((bData->userData->msgEncoding == UserData::ENCODING_IS91_EXTENDED_PROTOCOL)
330 || (bData->userData->msgEncoding == UserData::ENCODING_GSM_DCS)) {
331 outStream->write(8, bData->userData->msgType);
332 }
333 outStream->write(8, (bData->userData)->numFields);
334 outStream->writeByteVector(dataBits, (bData->userData)->payload);
335 if (paddingBits > 0)
336 outStream->write(paddingBits, 0);
337}
338
339void BearerData::encodeReplyOption(BearerData* bData,
340 shared_ptr<BitwiseOutputStream> outStream) {
341 outStream->write(8, 1);
342 outStream->write(1, bData->userAckReq ? 1 : 0);
343 outStream->write(1, bData->deliveryAckReq ? 1 : 0);
344 outStream->write(1, bData->readAckReq ? 1 : 0);
345 outStream->write(1, bData->reportReq ? 1 : 0);
346 outStream->write(4, 0);
347}
348
349//free memory
350std::vector<uint8_t> BearerData::encodeDtmfSmsAddress(std::string address) {
351 int digits = address.length();
352 int dataBits = digits * 4;
353 int dataBytes = (dataBits / 8);
354 dataBytes += (dataBits % 8) > 0 ? 1 : 0;
355 //uint8_t* rawData = new uint8_t[dataBytes];
356 std::vector<uint8_t> rawData;
357 for (int i = 0; i < digits; i++) {
358 char c = address[i];
359 int val = 0;
360 if ((c >= '1') && (c <= '9'))
361 val = c - '0';
362 else if (c == '0')
363 val = 10;
364 else if (c == '*')
365 val = 11;
366 else if (c == '#')
367 val = 12;
368 else
369 return rawData;
370 int size = rawData.size();
371 if ((i / 2) < size) {
372 rawData[i / 2] |= val << (4 - ((i % 2) * 4));
373 } else {
374 rawData.push_back(val << (4 - ((i % 2) * 4)));
375 }
376 }
377 return rawData;
378}
379
380void BearerData::encodeCdmaSmsAddress(std::shared_ptr<CdmaSmsAddress> addr) {
381 if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
382 //TBD
383// try {
384// addr.origBytes = addr.address.getBytes("US-ASCII");
385// } catch (java.io.UnsupportedEncodingException ex) {
386// throw new CodingException("invalid SMS address, cannot convert to ASCII");
387// }
388 } else {
389 addr->origBytes = encodeDtmfSmsAddress(addr->address);
390 }
391}
392
393void BearerData::encodeCallbackNumber(BearerData* bData,
394 shared_ptr<BitwiseOutputStream> outStream) {
395 auto addr = bData->callbackNumber;
396 encodeCdmaSmsAddress(addr);
397 int paramBits = 9;
398 int dataBits = 0;
399 if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
400 paramBits += 7;
401 dataBits = addr->numberOfDigits * 8;
402 } else {
403 dataBits = addr->numberOfDigits * 4;
404 }
405 paramBits += dataBits;
406 int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
407 int paddingBits = (paramBytes * 8) - paramBits;
408 outStream->write(8, paramBytes);
409 outStream->write(1, addr->digitMode);
410 if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
411 outStream->write(3, addr->ton);
412 outStream->write(4, addr->numberPlan);
413 }
414 outStream->write(8, addr->numberOfDigits);
415 outStream->writeByteVector(dataBits, addr->origBytes);
416 if (paddingBits > 0)
417 outStream->write(paddingBits, 0);
418}
419
420void BearerData::encodeMsgStatus(BearerData* bData,
421 shared_ptr<BitwiseOutputStream> outStream) {
422 outStream->write(8, 1);
423 outStream->write(2, bData->errorClass);
424 outStream->write(6, bData->messageStatus);
425}
426void BearerData::encodeMsgCount(BearerData* bData,
427 shared_ptr<BitwiseOutputStream> outStream) {
428 outStream->write(8, 1);
429 outStream->write(8, bData->numberOfMessages);
430}
431void BearerData::encodeValidityPeriodRel(BearerData* bData,
432 shared_ptr<BitwiseOutputStream> outStream) {
433 outStream->write(8, 1);
434 outStream->write(8, bData->validityPeriodRelative);
435}
436void BearerData::encodePrivacyIndicator(BearerData* bData,
437 shared_ptr<BitwiseOutputStream> outStream) {
438 outStream->write(8, 1);
439 outStream->write(2, bData->privacy);
440 outStream->skip(6);
441}
442void BearerData::encodeLanguageIndicator(BearerData* bData,
443 shared_ptr<BitwiseOutputStream> outStream) {
444 outStream->write(8, 1);
445 outStream->write(8, bData->language);
446}
447void BearerData::encodeDisplayMode(BearerData* bData,
448 shared_ptr<BitwiseOutputStream> outStream) {
449 outStream->write(8, 1);
450 outStream->write(2, bData->displayMode);
451 outStream->skip(6);
452}
453void BearerData::encodePriorityIndicator(BearerData* bData,
454 shared_ptr<BitwiseOutputStream> outStream) {
455 outStream->write(8, 1);
456 outStream->write(2, bData->priority);
457 outStream->skip(6);
458}
459void BearerData::encodeMsgDeliveryAlert(BearerData* bData,
460 shared_ptr<BitwiseOutputStream> outStream) {
461 outStream->write(8, 1);
462 outStream->write(2, bData->alert);
463 outStream->skip(6);
464}
465std::vector<uint8_t> BearerData::encode(BearerData* bData) {
466 bData->hasUserDataHeader = false; //((bData->userData != nullptr) && (bData->userData->userDataHeader != null));
467 shared_ptr<BitwiseOutputStream> outStream = make_shared<BitwiseOutputStream>(
468 200);
469 outStream->write(8, SUBPARAM_MESSAGE_IDENTIFIER);
470 encodeMessageId(bData, outStream);
471 if (bData->userData != nullptr) {
472 outStream->write(8, SUBPARAM_USER_DATA);
473 encodeUserData(bData, outStream);
474 //cout << "userData" << endl;
475 }
476 if (bData->callbackNumber != nullptr) {
477 //cout << "callbackNumber" << endl;
478 outStream->write(8, SUBPARAM_CALLBACK_NUMBER);
479 encodeCallbackNumber(bData, outStream);
480 }
481 if (bData->userAckReq || bData->deliveryAckReq || bData->readAckReq
482 || bData->reportReq) {
483 //cout << "userAckReq" << endl;
484 outStream->write(8, SUBPARAM_REPLY_OPTION);
485 encodeReplyOption(bData, outStream);
486 }
487 if (bData->numberOfMessages != 0) {
488 //cout << "numberOfMessages" << endl;
489 outStream->write(8, SUBPARAM_NUMBER_OF_MESSAGES);
490 encodeMsgCount(bData, outStream);
491 }
492 if (bData->validityPeriodRelativeSet) {
493 //cout << "validityPeriodRelativeSet" << endl;
494 outStream->write(8, SUBPARAM_VALIDITY_PERIOD_RELATIVE);
495 encodeValidityPeriodRel(bData, outStream);
496 }
497 if (bData->privacyIndicatorSet) {
498 //cout << "privacyIndicatorSet" << endl;
499 outStream->write(8, SUBPARAM_PRIVACY_INDICATOR);
500 encodePrivacyIndicator(bData, outStream);
501 }
502 if (bData->languageIndicatorSet) {
503 //cout << "languageIndicatorSet" << endl;
504 outStream->write(8, SUBPARAM_LANGUAGE_INDICATOR);
505 encodeLanguageIndicator(bData, outStream);
506 }
507 if (bData->displayModeSet) {
508 //cout << "displayModeSet" << endl;
509 outStream->write(8, SUBPARAM_MESSAGE_DISPLAY_MODE);
510 encodeDisplayMode(bData, outStream);
511 }
512 if (bData->priorityIndicatorSet) {
513 //cout << "priorityIndicatorSet" << endl;
514 outStream->write(8, SUBPARAM_PRIORITY_INDICATOR);
515 encodePriorityIndicator(bData, outStream);
516 }
517 if (bData->alertIndicatorSet) {
518 //cout << "alertIndicatorSet" << endl;
519 outStream->write(8, SUBPARAM_ALERT_ON_MESSAGE_DELIVERY);
520 encodeMsgDeliveryAlert(bData, outStream);
521 }
522 if (bData->messageStatusSet) {
523 //cout << "messageStatusSet" << endl;
524 outStream->write(8, SUBPARAM_MESSAGE_STATUS);
525 encodeMsgStatus(bData, outStream);
526 }
527// if (bData->serviceCategoryProgramResults != null) {
528// outStream->write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS);
529// encodeScpResults(bData, outStream);
530// }
531 return outStream->toByteVector();
532}
533
534std::shared_ptr<BearerData> BearerData::decode(std::vector<uint8_t> smsData) {
535 return decode(smsData, 0);
536}
537
538bool BearerData::decodeMessageId(std::shared_ptr<BearerData> bData,
539 std::shared_ptr<BitwiseInputStream> inStream) {
540 const int EXPECTED_PARAM_SIZE = 3 * 8;
541 bool decodeSuccess = false;
542 int paramBits = inStream->read(8) * 8;
543 if (paramBits >= EXPECTED_PARAM_SIZE) {
544 paramBits -= EXPECTED_PARAM_SIZE;
545 decodeSuccess = true;
546 bData->messageType = inStream->read(4);
547 bData->messageId = inStream->read(8) << 8;
548 bData->messageId |= inStream->read(8);
549 bData->hasUserDataHeader = (inStream->read(1) == 1);
550 inStream->skip(3);
551 }
552 if ((!decodeSuccess) || (paramBits > 0)) {
553// Rlog.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
554// (decodeSuccess ? "succeeded" : "failed") +
555// " (extra bits = " + paramBits + ")");
556 }
557 inStream->skip(paramBits);
558 return decodeSuccess;
559}
560
561bool BearerData::decodeUserData(std::shared_ptr<BearerData> bData,
562 std::shared_ptr<BitwiseInputStream> inStream) {
563 uint32_t paramBits = inStream->read((uint32_t) 8) * 8;
564 bData->userData = std::make_shared<UserData>();
565 bData->userData->msgEncoding = inStream->read(5);
566 bData->userData->msgEncodingSet = true;
567 bData->userData->msgType = 0;
568 int consumedBits = 5;
569 if ((bData->userData->msgEncoding == UserData::ENCODING_IS91_EXTENDED_PROTOCOL)
570 || (bData->userData->msgEncoding == UserData::ENCODING_GSM_DCS)) {
571 bData->userData->msgType = inStream->read(8);
572 consumedBits += 8;
573 }
574 bData->userData->numFields = inStream->read(8);
575 consumedBits += 8;
576 int dataBits = paramBits - consumedBits;
577 bData->userData->payload = inStream->readByteVector(dataBits);
578 return true;
579}
580
581bool BearerData::decodeUserResponseCode(std::shared_ptr<BearerData> bData,
582 std::shared_ptr<BitwiseInputStream> inStream) {
583 const uint32_t EXPECTED_PARAM_SIZE = 1 * 8;
584 bool decodeSuccess = false;
585 uint32_t paramBits = inStream->read(8) * 8;
586 if (paramBits >= EXPECTED_PARAM_SIZE) {
587 paramBits -= EXPECTED_PARAM_SIZE;
588 decodeSuccess = true;
589 bData->userResponseCode = inStream->read(8);
590 }
591 if ((!decodeSuccess) || (paramBits > 0)) {
592// Rlog.d(LOG_TAG, "USER_RESPONSE_CODE decode " +
593// (decodeSuccess ? "succeeded" : "failed") +
594// " (extra bits = " + paramBits + ")");
595 }
596 inStream->skip(paramBits);
597 bData->userResponseCodeSet = decodeSuccess;
598 return decodeSuccess;
599}
600
601bool BearerData::decodeReplyOption(std::shared_ptr<BearerData> bData,
602 std::shared_ptr<BitwiseInputStream> inStream) {
603 const int EXPECTED_PARAM_SIZE = 1 * 8;
604 bool decodeSuccess = false;
605 int paramBits = inStream->read(8) * 8;
606 if (paramBits >= EXPECTED_PARAM_SIZE) {
607 paramBits -= EXPECTED_PARAM_SIZE;
608 decodeSuccess = true;
609 bData->userAckReq = (inStream->read(1) == 1);
610 bData->deliveryAckReq = (inStream->read(1) == 1);
611 bData->readAckReq = (inStream->read(1) == 1);
612 bData->reportReq = (inStream->read(1) == 1);
613 inStream->skip(4);
614 }
615 if ((!decodeSuccess) || (paramBits > 0)) {
616// Rlog->d(LOG_TAG, "REPLY_OPTION decode " +
617// (decodeSuccess ? "succeeded" : "failed") +
618// " (extra bits = " + paramBits + ")");
619 }
620 inStream->skip(paramBits);
621 return decodeSuccess;
622}
623
624bool BearerData::decodeMsgCount(std::shared_ptr<BearerData> bData,
625 std::shared_ptr<BitwiseInputStream> inStream) {
626 const int EXPECTED_PARAM_SIZE = 1 * 8;
627 bool decodeSuccess = false;
628 int paramBits = inStream->read(8) * 8;
629 if (paramBits >= EXPECTED_PARAM_SIZE) {
630 paramBits -= EXPECTED_PARAM_SIZE;
631 decodeSuccess = true;
632 bData->numberOfMessages = IccUtils::cdmaBcdByteToInt(
633 (uint8_t) inStream->read(8));
634 }
635 if ((!decodeSuccess) || (paramBits > 0)) {
636// Rlog.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
637// (decodeSuccess ? "succeeded" : "failed") +
638// " (extra bits = " + paramBits + ")");
639 }
640 inStream->skip(paramBits);
641 return decodeSuccess;
642}
643
644std::string BearerData::decodeDtmfSmsAddress(std::vector<uint8_t> rawData,
645 int numFields) {
646 /* DTMF 4-bit digit encoding, defined in at
647 * 3GPP2 C.S005-D, v2.0, table 2.7.1.3.2.4-4 */
648 string strBuf;
649 for (int i = 0; i < numFields; i++) {
650 int val = 0x0F & (rawData[i / 2] >> (4 - ((i % 2) * 4)));
651 if ((val >= 1) && (val <= 9))
652 strBuf.append(to_string(val));
653 else if (val == 10)
654 strBuf.push_back('0');
655 else if (val == 11)
656 strBuf.push_back('*');
657 else if (val == 12)
658 strBuf.push_back('#');
659 else
660 throw runtime_error(
661 "invalid SMS address DTMF code (" + std::to_string(val) + ")");
662 }
663 return strBuf;
664}
665
666void BearerData::decodeSmsAddress(std::shared_ptr<CdmaSmsAddress> addr) {
667 if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
668 //android not support
669// try {
670// /* As specified in 3GPP2 C.S0015-B, v2, 4.5.15 -- actually
671// * just 7-bit ASCII encoding, with the MSB being zero. */
672// addr->address = new string(addr->origBytes, addr->origBytes_length);
673// } catch (exception& ex) {
674// throw runtime_error("invalid SMS address ASCII code");
675// }
676 } else {
677 addr->address = decodeDtmfSmsAddress(addr->origBytes, addr->numberOfDigits);
678 }
679}
680bool BearerData::decodeCallbackNumber(std::shared_ptr<BearerData> bData,
681 std::shared_ptr<BitwiseInputStream> inStream) {
682 const int EXPECTED_PARAM_SIZE = 1 * 8; //at least
683 int paramBits = inStream->read(8) * 8;
684 if (paramBits < EXPECTED_PARAM_SIZE) {
685 inStream->skip(paramBits);
686 return false;
687 }
688 std::shared_ptr<CdmaSmsAddress> addr = make_shared<CdmaSmsAddress>();
689 addr->digitMode = inStream->read(1);
690 uint8_t fieldBits = 4;
691 uint8_t consumedBits = 1;
692 if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
693 addr->ton = inStream->read(3);
694 addr->numberPlan = inStream->read(4);
695 fieldBits = 8;
696 consumedBits += 7;
697 }
698 addr->numberOfDigits = inStream->read(8);
699 consumedBits += 8;
700 int remainingBits = paramBits - consumedBits;
701 int dataBits = addr->numberOfDigits * fieldBits;
702 int paddingBits = remainingBits - dataBits;
703 if (remainingBits < dataBits) {
704 throw runtime_error(
705 string("CALLBACK_NUMBER subparam encoding size error (")
706 + string("remainingBits + ") + std::to_string(remainingBits)
707 + string(", dataBits + ") + std::to_string(dataBits)
708 + string(", paddingBits + ") + std::to_string(paddingBits)
709 + string(")"));
710 }
711 addr->origBytes = inStream->readByteVector(dataBits);
712 inStream->skip(paddingBits);
713 decodeSmsAddress(addr);
714 bData->callbackNumber = addr;
715 return true;
716}
717
718bool BearerData::decodeMsgStatus(std::shared_ptr<BearerData> bData,
719 std::shared_ptr<BitwiseInputStream> inStream) {
720 const int EXPECTED_PARAM_SIZE = 1 * 8;
721 bool decodeSuccess = false;
722 int paramBits = inStream->read(8) * 8;
723 if (paramBits >= EXPECTED_PARAM_SIZE) {
724 paramBits -= EXPECTED_PARAM_SIZE;
725 decodeSuccess = true;
726 bData->errorClass = inStream->read(2);
727 bData->messageStatus = inStream->read(6);
728 }
729 if ((!decodeSuccess) || (paramBits > 0)) {
730// Rlog.d(LOG_TAG, "MESSAGE_STATUS decode " +
731// (decodeSuccess ? "succeeded" : "failed") +
732// " (extra bits = " + paramBits + ")");
733 }
734 inStream->skip(paramBits);
735 bData->messageStatusSet = decodeSuccess;
736 return decodeSuccess;
737}
738
739bool BearerData::decodeMsgCenterTimeStamp(std::shared_ptr<BearerData> bData,
740 std::shared_ptr<BitwiseInputStream> inStream) {
741 const int EXPECTED_PARAM_SIZE = 6 * 8;
742 bool decodeSuccess = false;
743 int paramBits = inStream->read(8) * 8;
744 if (paramBits >= EXPECTED_PARAM_SIZE) {
745 paramBits -= EXPECTED_PARAM_SIZE;
746 decodeSuccess = true;
747 fromByteArray(inStream->readByteVector(6 * 8), bData->msgCenterTimeStamp);
748 }
749 if ((!decodeSuccess) || (paramBits > 0)) {
750 /* Rlog.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
751 (decodeSuccess ? "succeeded" : "failed") +
752 " (extra bits = " + paramBits + ")");*/
753 }
754 inStream->skip(paramBits);
755 return decodeSuccess;
756}
757
758bool BearerData::decodeValidityAbs(std::shared_ptr<BearerData> bData,
759 std::shared_ptr<BitwiseInputStream> inStream) {
760 const int EXPECTED_PARAM_SIZE = 6 * 8;
761 bool decodeSuccess = false;
762 int paramBits = inStream->read(8) * 8;
763 if (paramBits >= EXPECTED_PARAM_SIZE) {
764 paramBits -= EXPECTED_PARAM_SIZE;
765 decodeSuccess = true;
766 fromByteArray(inStream->readByteVector(6 * 8),
767 bData->validityPeriodAbsolute);
768 }
769 if ((!decodeSuccess) || (paramBits > 0)) {
770// Rlog.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
771// (decodeSuccess ? "succeeded" : "failed") +
772// " (extra bits = " + paramBits + ")");
773 }
774 inStream->skip(paramBits);
775 return decodeSuccess;
776}
777
778bool BearerData::decodeValidityRel(std::shared_ptr<BearerData> bData,
779 std::shared_ptr<BitwiseInputStream> inStream) {
780 const int EXPECTED_PARAM_SIZE = 1 * 8;
781 bool decodeSuccess = false;
782 int paramBits = inStream->read(8) * 8;
783 if (paramBits >= EXPECTED_PARAM_SIZE) {
784 paramBits -= EXPECTED_PARAM_SIZE;
785 decodeSuccess = true;
786 //bData->deferredDeliveryTimeRelative = inStream->read(8);
787 bData->validityPeriodRelative = inStream->read(8);
788 }
789 if ((!decodeSuccess) || (paramBits > 0)) {
790 /* Rlog.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
791 (decodeSuccess ? "succeeded" : "failed") +
792 " (extra bits = " + paramBits + ")");*/
793 }
794 inStream->skip(paramBits);
795 //bData->deferredDeliveryTimeRelativeSet = decodeSuccess;
796 bData->validityPeriodRelativeSet = decodeSuccess;
797 return decodeSuccess;
798}
799
800bool BearerData::decodeDeferredDeliveryAbs(std::shared_ptr<BearerData> bData,
801 std::shared_ptr<BitwiseInputStream> inStream) {
802 const int EXPECTED_PARAM_SIZE = 6 * 8;
803 bool decodeSuccess = false;
804 int paramBits = inStream->read(8) * 8;
805 if (paramBits >= EXPECTED_PARAM_SIZE) {
806 paramBits -= EXPECTED_PARAM_SIZE;
807 decodeSuccess = true;
808 fromByteArray(inStream->readByteVector(6 * 8),
809 bData->deferredDeliveryTimeAbsolute);
810 }
811 if ((!decodeSuccess) || (paramBits > 0)) {
812 /* Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
813 (decodeSuccess ? "succeeded" : "failed") +
814 " (extra bits = " + paramBits + ")");*/
815 }
816 inStream->skip(paramBits);
817 return decodeSuccess;
818}
819
820bool BearerData::decodeDeferredDeliveryRel(std::shared_ptr<BearerData> bData,
821 std::shared_ptr<BitwiseInputStream> inStream) {
822 const int EXPECTED_PARAM_SIZE = 1 * 8;
823 bool decodeSuccess = false;
824 int paramBits = inStream->read(8) * 8;
825 if (paramBits >= EXPECTED_PARAM_SIZE) {
826 paramBits -= EXPECTED_PARAM_SIZE;
827 decodeSuccess = true;
828 //bData->validityPeriodRelative = inStream->read(8);
829 bData->deferredDeliveryTimeRelative = inStream->read(8);
830 }
831 if ((!decodeSuccess) || (paramBits > 0)) {
832 /* Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
833 (decodeSuccess ? "succeeded" : "failed") +
834 " (extra bits = " + paramBits + ")");*/
835 }
836 inStream->skip(paramBits);
837 //bData->validityPeriodRelativeSet = decodeSuccess;
838 bData->deferredDeliveryTimeRelativeSet = decodeSuccess;
839 return decodeSuccess;
840}
841
842bool BearerData::decodePrivacyIndicator(std::shared_ptr<BearerData> bData,
843 std::shared_ptr<BitwiseInputStream> inStream) {
844 const int EXPECTED_PARAM_SIZE = 1 * 8;
845 bool decodeSuccess = false;
846 int paramBits = inStream->read(8) * 8;
847 if (paramBits >= EXPECTED_PARAM_SIZE) {
848 paramBits -= EXPECTED_PARAM_SIZE;
849 decodeSuccess = true;
850 bData->privacy = inStream->read(2);
851 inStream->skip(6);
852 }
853 if ((!decodeSuccess) || (paramBits > 0)) {
854 /* Rlog.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
855 (decodeSuccess ? "succeeded" : "failed") +
856 " (extra bits = " + paramBits + ")");*/
857 }
858 inStream->skip(paramBits);
859 bData->privacyIndicatorSet = decodeSuccess;
860 return decodeSuccess;
861}
862bool BearerData::decodeLanguageIndicator(std::shared_ptr<BearerData> bData,
863 std::shared_ptr<BitwiseInputStream> inStream) {
864 const int EXPECTED_PARAM_SIZE = 1 * 8;
865 bool decodeSuccess = false;
866 int paramBits = inStream->read(8) * 8;
867 if (paramBits >= EXPECTED_PARAM_SIZE) {
868 paramBits -= EXPECTED_PARAM_SIZE;
869 decodeSuccess = true;
870 bData->language = inStream->read(8);
871 }
872 if ((!decodeSuccess) || (paramBits > 0)) {
873 /* Rlog.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
874 (decodeSuccess ? "succeeded" : "failed") +
875 " (extra bits = " + paramBits + ")");*/
876 }
877 inStream->skip(paramBits);
878 bData->languageIndicatorSet = decodeSuccess;
879 return decodeSuccess;
880}
881
882bool BearerData::decodeDisplayMode(std::shared_ptr<BearerData> bData,
883 std::shared_ptr<BitwiseInputStream> inStream) {
884 const int EXPECTED_PARAM_SIZE = 1 * 8;
885 bool decodeSuccess = false;
886 int paramBits = inStream->read(8) * 8;
887 if (paramBits >= EXPECTED_PARAM_SIZE) {
888 paramBits -= EXPECTED_PARAM_SIZE;
889 decodeSuccess = true;
890 bData->displayMode = inStream->read(2);
891 inStream->skip(6);
892 }
893// if ((! decodeSuccess) || (paramBits > 0)) {
894// Rlog.d(LOG_TAG, "DISPLAY_MODE decode " +
895// (decodeSuccess ? "succeeded" : "failed") +
896// " (extra bits = " + paramBits + ")");
897// }
898 inStream->skip(paramBits);
899 bData->displayModeSet = decodeSuccess;
900 return decodeSuccess;
901}
902
903bool BearerData::decodePriorityIndicator(std::shared_ptr<BearerData> bData,
904 std::shared_ptr<BitwiseInputStream> inStream) {
905 const int EXPECTED_PARAM_SIZE = 1 * 8;
906 bool decodeSuccess = false;
907 int paramBits = inStream->read(8) * 8;
908 if (paramBits >= EXPECTED_PARAM_SIZE) {
909 paramBits -= EXPECTED_PARAM_SIZE;
910 decodeSuccess = true;
911 bData->priority = inStream->read(2);
912 inStream->skip(6);
913 }
914// if ((! decodeSuccess) || (paramBits > 0)) {
915// Rlog.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
916// (decodeSuccess ? "succeeded" : "failed") +
917// " (extra bits = " + paramBits + ")");
918// }
919 inStream->skip(paramBits);
920 bData->priorityIndicatorSet = decodeSuccess;
921 return decodeSuccess;
922}
923
924bool BearerData::decodeMsgDeliveryAlert(std::shared_ptr<BearerData> bData,
925 std::shared_ptr<BitwiseInputStream> inStream) {
926 const int EXPECTED_PARAM_SIZE = 1 * 8;
927 bool decodeSuccess = false;
928 int paramBits = inStream->read(8) * 8;
929 if (paramBits >= EXPECTED_PARAM_SIZE) {
930 paramBits -= EXPECTED_PARAM_SIZE;
931 decodeSuccess = true;
932 bData->alert = inStream->read(2);
933 inStream->skip(6);
934 }
935 if ((!decodeSuccess) || (paramBits > 0)) {
936// Rlog.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
937// (decodeSuccess ? "succeeded" : "failed") +
938// " (extra bits = " + paramBits + ")");
939 }
940 inStream->skip(paramBits);
941 bData->alertIndicatorSet = decodeSuccess;
942 return decodeSuccess;
943}
944
945bool BearerData::decodeDepositIndex(std::shared_ptr<BearerData> bData,
946 std::shared_ptr<BitwiseInputStream> inStream) {
947 const int EXPECTED_PARAM_SIZE = 2 * 8;
948 bool decodeSuccess = false;
949 int paramBits = inStream->read(8) * 8;
950 if (paramBits >= EXPECTED_PARAM_SIZE) {
951 paramBits -= EXPECTED_PARAM_SIZE;
952 decodeSuccess = true;
953 bData->depositIndex = (inStream->read(8) << 8) | inStream->read(8);
954 }
955 /* if ((! decodeSuccess) || (paramBits > 0)) {
956 Rlog.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
957 (decodeSuccess ? "succeeded" : "failed") +
958 " (extra bits = " + paramBits + ")");
959 }*/
960 inStream->skip(paramBits);
961 return decodeSuccess;
962}
963
964int BearerData::getBitsForNumFields(int msgEncoding, int numFields) {
965 switch (msgEncoding) {
966 case UserData::ENCODING_OCTET:
967 case UserData::ENCODING_SHIFT_JIS:
968 case UserData::ENCODING_KOREAN:
969 case UserData::ENCODING_LATIN:
970 case UserData::ENCODING_LATIN_HEBREW:
971 return numFields * 8;
972
973 case UserData::ENCODING_IA5:
974 case UserData::ENCODING_7BIT_ASCII:
975 case UserData::ENCODING_GSM_7BIT_ALPHABET:
976 return numFields * 7;
977
978 case UserData::ENCODING_UNICODE_16:
979 return numFields * 16;
980
981 default:
982 throw runtime_error("unsupported message encoding (" + msgEncoding + ')');
983 }
984}
985
986std::string BearerData::decodeUtf8(std::vector<uint8_t> data, int offset, int numFields)
987{
988 std::string str;
989 for (int i = offset; i < (offset + numFields); i++)
990 {
991 str.push_back((char)data[i]);
992 }
993 return str;
994}
995
996std::string BearerData::decodeLatin(std::vector<uint8_t> data, int offset, int numFields)
997{
998 std::string str;
999 for (int i = offset; i < (offset + numFields); i++)
1000 {
1001 str.push_back(data[i]);
1002 }
1003 char* text = g_convert (str.c_str(), numFields, "UTF-8", "ISO−8859−1", NULL, NULL, NULL);
1004 if(!text) {
1005 printf("convert (Latin) result is null\n");
1006 return std::string("");
1007 }
1008 std::string ret(text);
1009 g_free(text);
1010 return ret;
1011}
1012
1013std::string BearerData::decodeUtf16(std::vector<uint8_t> data, int offset, int numFields)
1014{
1015 std::string str;
1016 for (int i = offset; i < (offset + numFields*2); i++)
1017 {
1018 str.push_back((char)data[i]);
1019 }
1020 char* text = g_convert (str.c_str(), numFields*2, "UTF-8", "UCS-2BE", NULL, NULL, NULL);
1021 if(!text) {
1022 printf("convert (Utf16) result is null\n");
1023 return std::string("");
1024 }
1025 std::string ret(text);
1026 g_free(text);
1027 text = NULL;
1028 return ret;
1029}
1030
1031std::string BearerData::decode7bitAscii(std::vector<uint8_t> data, int offset,
1032 int numFields) {
1033 int headerSeptets = (offset * 8 + 6) / 7;
1034 numFields -= headerSeptets;
1035 std::string strBuf;
1036 auto inStream = std::make_shared<BitwiseInputStream>(data);
1037 int wantedBits = (headerSeptets + numFields) * 7;
1038 if (inStream->available() < wantedBits) {
1039 throw runtime_error(
1040 "insufficient data (wanted " + std::to_string(wantedBits)
1041 + " bits, but only have " + std::to_string(inStream->available())
1042 + ")");
1043 }
1044 inStream->skip(headerSeptets * 7);
1045 for (int i = 0; i < numFields; i++) {
1046 int charCode = inStream->read(7);
1047 if ((charCode >= UserData::ASCII_MAP_BASE_INDEX)
1048 && (charCode <= UserData::ASCII_MAP_MAX_INDEX)) {
1049 strBuf.push_back(
1050 UserData::ASCII_MAP[charCode - UserData::ASCII_MAP_BASE_INDEX]);
1051 } else if (charCode == UserData::ASCII_NL_INDEX) {
1052 strBuf.push_back('\n');
1053 } else if (charCode == UserData::ASCII_CR_INDEX) {
1054 strBuf.push_back('\r');
1055 } else {
1056 /* For other charCodes, they are unprintable, and so simply use SPACE. */
1057 strBuf.push_back(' ');
1058 }
1059 }
1060 return strBuf;
1061}
1062
1063std::string BearerData::decode7bitGsm(std::vector<uint8_t> data, int offset,
1064 int numFields) {
1065 // Start reading from the next 7-bit aligned boundary after offset.
1066 int offsetBits = offset * 8;
1067 int offsetSeptets = (offsetBits + 6) / 7;
1068 numFields -= offsetSeptets;
1069 int paddingBits = (offsetSeptets * 7) - offsetBits;
1070 string result = GsmAlphabet::gsm7BitPackedToString(data, offset, numFields,
1071 paddingBits, 0, 0);
1072 if (result.empty()) {
1073 throw runtime_error("7bit GSM decoding failed");
1074 }
1075 return result;
1076}
1077
1078std::string BearerData::decodeGsmDcs(std::vector<uint8_t> data, int offset,
1079 int numFields, int msgType) {
1080 if ((msgType & 0xC0) != 0) {
1081 throw runtime_error(
1082 "unsupported coding group (" + std::to_string(msgType) + ")");
1083 }
1084
1085 switch ((msgType >> 2) & 0x3) {
1086 case UserData::ENCODING_GSM_DCS_7BIT:
1087 return decode7bitGsm(data, offset, numFields);
1088// case UserData.ENCODING_GSM_DCS_8BIT:
1089// return decodeUtf8(data, offset, numFields);
1090// case UserData.ENCODING_GSM_DCS_16BIT:
1091// return decodeUtf16(data, offset, numFields);
1092 default:
1093 throw runtime_error(
1094 "unsupported user msgType encoding (" + std::to_string(msgType) + ")");
1095 }
1096}
1097
1098void BearerData::decodeUserDataPayload(std::shared_ptr<UserData> userData,
1099 bool hasUserDataHeader) {
1100 int offset = 0;
1101 //printf("1st,%s\n",userData->toString().c_str());
1102 if (hasUserDataHeader) {
1103 int udhLen = userData->payload[0] & 0x00FF;
1104 offset += udhLen + 1;
1105 /* byte[] headerData = new byte[udhLen];
1106 System.arraycopy(userData.payload, 1, headerData, 0, udhLen)*/;
1107 std::vector<uint8_t> v;
1108 v.insert(v.end(), userData->payload.begin() + 1,
1109 userData->payload.begin() + udhLen);
1110 userData->userDataHeader = SmsHeader::fromByteArray(v);
1111 //for test cdma long sms, SmsHeader::fromByteArray get the sequence number,but it will always be the last sequence,
1112 //maybe overwriten by the last sms part. we print here directly as a temporary solution.
1113 if(udhLen == 5 && (userData->payload[1] & 0x00FF)==0x00)//0x00 is the concatenated SMS id
1114 {
1115 printf("udhLen=%d,refNumber=%d,msgCount=%d, seqNumber=%d\n", udhLen,
1116 userData->payload[3] & 0x00FF,userData->payload[4] & 0x00FF,userData->payload[5] & 0x00FF);
1117 }
1118 else{
1119 printf("udhLen=%d, not for test format!\n",udhLen);
1120 }
1121 }
1122 //add for long sms test begin
1123 //printf("offset: %d\n",offset);
1124 //printf("2nd,%s\n",userData->toString().c_str());
1125 //add for long sms test end
1126 switch (userData->msgEncoding) {
1127 case UserData::ENCODING_OCTET: {
1128 /*
1129 * Octet decoding depends on the carrier service.
1130 */
1131 bool decodingtypeUTF8 = true;
1132
1133 // Strip off any padding bytes, meaning any differences between the length of the
1134 // array and the target length specified by numFields. This is to avoid any
1135 // confusion by code elsewhere that only considers the payload array length.
1136 int copyLen = userData->numFields < userData->payload.size() ? userData->numFields : userData->payload.size();
1137 std::vector<uint8_t> payload;
1138 payload.insert(payload.end(), userData->payload.begin(), userData->payload.begin() + copyLen);
1139 userData->payload = payload;
1140
1141 if (!decodingtypeUTF8) {
1142 // There are many devices in the market that send 8bit text sms (latin encoded) as
1143 // octet encoded.
1144 userData->payloadStr = decodeLatin(userData->payload, offset, userData->numFields);
1145 } else {
1146 userData->payloadStr = decodeUtf8(userData->payload, offset, userData->numFields);
1147 }
1148 break;
1149 }
1150 case UserData::ENCODING_IA5:
1151 case UserData::ENCODING_7BIT_ASCII: {
1152 userData->payloadStr = decode7bitAscii(userData->payload, offset, userData->numFields);
1153 break;
1154 case UserData::ENCODING_UNICODE_16:
1155 userData->payloadStr = decodeUtf16(userData->payload, offset, userData->numFields);
1156 break;
1157 }
1158 case UserData::ENCODING_GSM_7BIT_ALPHABET: {
1159 userData->payloadStr = decode7bitGsm(userData->payload, offset, userData->numFields);
1160 break;
1161 }
1162 case UserData::ENCODING_LATIN:
1163 userData->payloadStr = decodeLatin(userData->payload, offset, userData->numFields);
1164 break;
1165// case UserData::ENCODING_SHIFT_JIS:
1166// // userData->payloadStr = decodeShiftJis(userData->payload, offset, userData->numFields);
1167// //TBD "unsupported user data encoding"
1168// break;
1169 case UserData::ENCODING_GSM_DCS: {
1170 userData->payloadStr = decodeGsmDcs(userData->payload, offset,
1171 userData->numFields, userData->msgType);
1172 break;
1173 }
1174 default:
1175 printf("unsupported user data encoding : %\n" ,std::to_string(userData->msgEncoding));
1176// throw runtime_error(
1177// "unsupported user data encoding ("
1178// + std::to_string(userData->msgEncoding) + ")");
1179 }
1180}
1181bool BearerData::decodeServiceCategoryProgramData(
1182 std::shared_ptr<BearerData> bData,
1183 std::shared_ptr<BitwiseInputStream> inStream) {
1184 if (inStream->available() < 13) {
1185 throw runtime_error(
1186 string("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only ")
1187 + std::to_string(inStream->available())
1188 + string(" bits available"));
1189 }
1190
1191 int paramBits = inStream->read(8) * 8;
1192 int msgEncoding = inStream->read(5);
1193 paramBits -= 5;
1194
1195 if (inStream->available() < paramBits) {
1196 throw runtime_error(
1197 string("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only ")
1198 + std::to_string(inStream->available())
1199 + string(" bits available (") + std::to_string(paramBits)
1200 + string(" bits expected)"));
1201 }
1202
1203 auto programDataList = make_shared<list<shared_ptr<CdmaSmsCbProgramData>>>();
1204 const int CATEGORY_FIELD_MIN_SIZE = 6 * 8;
1205 bool decodeSuccess = false;
1206 while (paramBits >= CATEGORY_FIELD_MIN_SIZE) {
1207 int operation = inStream->read(4);
1208 int category = (inStream->read(8) << 8) | inStream->read(8);
1209 int language = inStream->read(8);
1210 int maxMessages = inStream->read(8);
1211 int alertOption = inStream->read(4);
1212 int numFields = inStream->read(8);
1213 paramBits -= CATEGORY_FIELD_MIN_SIZE;
1214
1215 int textBits = getBitsForNumFields(msgEncoding, numFields);
1216 if (paramBits < textBits) {
1217 throw runtime_error(
1218 string("category name is ") + std::to_string(textBits)
1219 + string(" bits in length,") + string(" but there are only ")
1220 + std::to_string(paramBits) + string(" bits available"));
1221 }
1222
1223 auto userData = make_shared<UserData>();
1224 userData->msgEncoding = msgEncoding;
1225 userData->msgEncodingSet = true;
1226 userData->numFields = numFields;
1227 userData->payload = inStream->readByteVector(textBits);
1228 paramBits -= textBits;
1229
1230 decodeUserDataPayload(userData, false);
1231 string categoryName = userData->payloadStr;
1232 auto programData = std::make_shared<CdmaSmsCbProgramData>(operation,
1233 category, language, maxMessages, alertOption, categoryName);
1234 programDataList->push_back(programData);
1235
1236 decodeSuccess = true;
1237 }
1238
1239 if ((!decodeSuccess) || (paramBits > 0)) {
1240// Rlog.d(LOG_TAG, "SERVICE_CATEGORY_PROGRAM_DATA decode " +
1241// (decodeSuccess ? "succeeded" : "failed") +
1242// " (extra bits = " + paramBits + ')');
1243 }
1244
1245 inStream->skip(paramBits);
1246 bData->serviceCategoryProgramData = programDataList;
1247 return decodeSuccess;
1248}
1249
1250bool BearerData::decodeReserved(std::shared_ptr<BearerData> bData,
1251 std::shared_ptr<BitwiseInputStream> inStream, int subparamId) {
1252 bool decodeSuccess = false;
1253 int subparamLen = inStream->read(8); // SUBPARAM_LEN
1254 int paramBits = subparamLen * 8;
1255 if (paramBits <= inStream->available()) {
1256 decodeSuccess = true;
1257 inStream->skip(paramBits);
1258 }
1259// Rlog.d(LOG_TAG, "RESERVED bearer data subparameter " + subparamId + " decode "
1260// + (decodeSuccess ? "succeeded" : "failed") + " (param bits = " + paramBits + ")");
1261 if (!decodeSuccess) {
1262 throw runtime_error(
1263 "RESERVED bearer data subparameter " + std::to_string(subparamId)
1264 + " had invalid SUBPARAM_LEN " + std::to_string(subparamLen));
1265 }
1266
1267 return decodeSuccess;
1268}
1269bool BearerData::isCmasAlertCategory(int category) {
1270 return category >= SmsEnvelope::SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT
1271 && category <= SmsEnvelope::SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE;
1272}
1273
1274int BearerData::serviceCategoryToCmasMessageClass(int serviceCategory) {
1275 switch (serviceCategory) {
1276 case SmsEnvelope::SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT:
1277 return SmsCbCmasInfo::CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT;
1278
1279 case SmsEnvelope::SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
1280 return SmsCbCmasInfo::CMAS_CLASS_EXTREME_THREAT;
1281
1282 case SmsEnvelope::SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
1283 return SmsCbCmasInfo::CMAS_CLASS_SEVERE_THREAT;
1284
1285 case SmsEnvelope::SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
1286 return SmsCbCmasInfo::CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY;
1287
1288 case SmsEnvelope::SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
1289 return SmsCbCmasInfo::CMAS_CLASS_REQUIRED_MONTHLY_TEST;
1290
1291 default:
1292 return SmsCbCmasInfo::CMAS_CLASS_UNKNOWN;
1293 }
1294}
1295void BearerData::decodeCmasUserData(std::shared_ptr<BearerData> bData,
1296 int serviceCategory) {
1297 //uint8_t array[bData->userData->payload.size()];
1298 //std::copy(bData->userData->payload.begin(), bData->userData->payload.end(), array);
1299 auto inStream = make_shared<BitwiseInputStream>(bData->userData->payload);
1300
1301 if (inStream->available() < 8) {
1302 throw runtime_error("emergency CB with no CMAE_protocol_version");
1303 }
1304 int protocolVersion = inStream->read(8);
1305 if (protocolVersion != 0) {
1306 throw runtime_error("unsupported CMAE_protocol_version " + protocolVersion);
1307 }
1308
1309 int messageClass = serviceCategoryToCmasMessageClass(serviceCategory);
1310 int category = SmsCbCmasInfo::CMAS_CATEGORY_UNKNOWN;
1311 int responseType = SmsCbCmasInfo::CMAS_RESPONSE_TYPE_UNKNOWN;
1312 int severity = SmsCbCmasInfo::CMAS_SEVERITY_UNKNOWN;
1313 int urgency = SmsCbCmasInfo::CMAS_URGENCY_UNKNOWN;
1314 int certainty = SmsCbCmasInfo::CMAS_CERTAINTY_UNKNOWN;
1315
1316 while (inStream->available() >= 16) {
1317 int recordType = inStream->read(8);
1318 int recordLen = inStream->read(8);
1319 switch (recordType) {
1320 case 0: // Type 0 elements (Alert text)
1321 {
1322 auto alertUserData = make_shared<UserData>();
1323 alertUserData->msgEncoding = inStream->read(5);
1324 alertUserData->msgEncodingSet = true;
1325 alertUserData->msgType = 0;
1326
1327 int numFields; // number of chars to decode
1328 switch (alertUserData->msgEncoding) {
1329 case UserData::ENCODING_OCTET:
1330 case UserData::ENCODING_LATIN:
1331 numFields = recordLen - 1; // subtract 1 byte for encoding
1332 break;
1333
1334 case UserData::ENCODING_IA5:
1335 case UserData::ENCODING_7BIT_ASCII:
1336 case UserData::ENCODING_GSM_7BIT_ALPHABET:
1337 numFields = ((recordLen * 8) - 5) / 7; // subtract 5 bits for encoding
1338 break;
1339
1340 case UserData::ENCODING_UNICODE_16:
1341 numFields = (recordLen - 1) / 2;
1342 break;
1343
1344 default:
1345 numFields = 0; // unsupported encoding
1346 }
1347
1348 alertUserData->numFields = numFields;
1349 alertUserData->payload = inStream->readByteVector(recordLen * 8 - 5);
1350 decodeUserDataPayload(alertUserData, false);
1351 bData->userData = alertUserData;
1352 break;
1353 }
1354 case 1: // Type 1 elements
1355 {
1356 category = inStream->read(8);
1357 responseType = inStream->read(8);
1358 severity = inStream->read(4);
1359 urgency = inStream->read(4);
1360 certainty = inStream->read(4);
1361 inStream->skip(recordLen * 8 - 28);
1362 break;
1363 }
1364 default:
1365 //Rlog.w(LOG_TAG, "skipping unsupported CMAS record type " + recordType);
1366 inStream->skip(recordLen * 8);
1367 break;
1368 }
1369 }
1370
1371 bData->cmasWarningInfo = make_shared<SmsCbCmasInfo>(messageClass, category,
1372 responseType, severity, urgency, certainty);
1373}
1374
1375void BearerData::decodeIs91VoicemailStatus(std::shared_ptr<BearerData> bData) {
1376 //uint8_t array[bData->userData->payload.size()];
1377 //std::copy(bData->userData->payload.begin(), bData->userData->payload.end(), array);
1378 auto inStream = make_shared<BitwiseInputStream>(bData->userData->payload);
1379
1380 int dataLen = inStream->available() / 6; // 6-bit packed character encoding.
1381 int numFields = bData->userData->numFields;
1382 if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
1383 throw runtime_error("IS-91 voicemail status decoding failed");
1384 }
1385 string strbuf;
1386 while (inStream->available() >= 6) {
1387 strbuf.push_back(UserData::ASCII_MAP[inStream->read(6)]);
1388 }
1389 string data = strbuf;
1390 bData->numberOfMessages = std::stoi(data.substr(0, 2));
1391 char prioCode = data.at(2);
1392 if (prioCode == ' ') {
1393 bData->priority = PRIORITY_NORMAL;
1394 } else if (prioCode == '!') {
1395 bData->priority = PRIORITY_URGENT;
1396 } else {
1397 throw runtime_error(
1398 string("IS-91 voicemail status decoding failed: ")
1399 + string("illegal priority setting (") + std::to_string(prioCode)
1400 + string(")"));
1401 }
1402 bData->priorityIndicatorSet = true;
1403 bData->userData->payloadStr = data.substr(3, numFields - 6);
1404}
1405void BearerData::decodeIs91Cli(std::shared_ptr<BearerData> bData) {
1406 //uint8_t array[bData->userData->payload.size()];
1407 //std::copy(bData->userData->payload.begin(), bData->userData->payload.end(), array);
1408 auto inStream = make_shared<BitwiseInputStream>(bData->userData->payload);
1409 int dataLen = inStream->available() / 4; // 4-bit packed DTMF digit encoding.
1410 int numFields = bData->userData->numFields;
1411 if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
1412 throw runtime_error("IS-91 voicemail status decoding failed");
1413 }
1414 auto addr = make_shared<CdmaSmsAddress>();
1415 addr->digitMode = CdmaSmsAddress::DIGIT_MODE_4BIT_DTMF;
1416 addr->origBytes = bData->userData->payload;
1417 addr->numberOfDigits = (uint8_t) numFields;
1418 decodeSmsAddress(addr);
1419 bData->callbackNumber = addr;
1420}
1421
1422void BearerData::decodeIs91ShortMessage(std::shared_ptr<BearerData> bData) {
1423 //uint8_t array[bData->userData->payload.size()];
1424 //std::copy(bData->userData->payload.begin(), bData->userData->payload.end(), array);
1425 auto inStream = make_shared<BitwiseInputStream>(bData->userData->payload);
1426 int dataLen = inStream->available() / 6; // 6-bit packed character encoding.
1427 int numFields = bData->userData->numFields;
1428 // dataLen may be > 14 characters due to octet padding
1429 if ((numFields > 14) || (dataLen < numFields)) {
1430 throw runtime_error("IS-91 short message decoding failed");
1431 }
1432 string strbuf;
1433 for (int i = 0; i < numFields; i++) {
1434 strbuf.push_back(UserData::ASCII_MAP[inStream->read(6)]);
1435 }
1436 bData->userData->payloadStr = strbuf;
1437}
1438
1439void BearerData::decodeIs91(std::shared_ptr<BearerData> bData) {
1440 switch (bData->userData->msgType) {
1441 case UserData::IS91_MSG_TYPE_VOICEMAIL_STATUS:
1442 decodeIs91VoicemailStatus(bData);
1443 break;
1444 case UserData::IS91_MSG_TYPE_CLI:
1445 decodeIs91Cli(bData);
1446 break;
1447 case UserData::IS91_MSG_TYPE_SHORT_MESSAGE_FULL:
1448 case UserData::IS91_MSG_TYPE_SHORT_MESSAGE:
1449 decodeIs91ShortMessage(bData);
1450 break;
1451 default:
1452 throw runtime_error(
1453 string("unsupported IS-91 message type (")
1454 + std::to_string(bData->userData->msgType) + string(")"));
1455 }
1456}
1457std::shared_ptr<BearerData> BearerData::decode(std::vector<uint8_t> smsData,
1458 int serviceCategory) {
1459 //uint8_t array[smsData.size()];
1460 //std::copy(smsData.begin(), smsData.end(), array);
1461 auto inStream = make_shared<BitwiseInputStream>(smsData);
1462 shared_ptr<BearerData> bData = make_shared<BearerData>();
1463 int foundSubparamMask = 0;
1464 while (inStream->available() > 0) {
1465 uint32_t subparamId = inStream->read((uint32_t) 8);
1466 int subparamIdBit = 1 << subparamId;
1467 // int is 4 bytes. This duplicate check has a limit to Id number up to 32 (4*8)
1468 // as 32th bit is the max bit in int.
1469 // Per 3GPP2 C.S0015-B Table 4.5-1 Bearer Data Subparameter Identifiers:
1470 // last defined subparam ID is 23 (00010111 = 0x17 = 23).
1471 // Only do duplicate subparam ID check if subparam is within defined value as
1472 // reserved subparams are just skipped.
1473 if ((foundSubparamMask & subparamIdBit) != 0
1474 && (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER
1475 && subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
1476 throw runtime_error(
1477 string("illegal duplicate subparameter (")
1478 + std::to_string(subparamId) + string(")"));
1479 }
1480 bool decodeSuccess;
1481 switch (subparamId) {
1482 case SUBPARAM_MESSAGE_IDENTIFIER:
1483 decodeSuccess = decodeMessageId(bData, inStream);
1484 break;
1485 case SUBPARAM_USER_DATA:
1486 decodeSuccess = decodeUserData(bData, inStream);
1487 break;
1488 case SUBPARAM_USER_RESPONSE_CODE:
1489 decodeSuccess = decodeUserResponseCode(bData, inStream);
1490 break;
1491 case SUBPARAM_REPLY_OPTION:
1492 decodeSuccess = decodeReplyOption(bData, inStream);
1493 break;
1494 case SUBPARAM_NUMBER_OF_MESSAGES:
1495 decodeSuccess = decodeMsgCount(bData, inStream);
1496 break;
1497 case SUBPARAM_CALLBACK_NUMBER:
1498 decodeSuccess = decodeCallbackNumber(bData, inStream);
1499 break;
1500 case SUBPARAM_MESSAGE_STATUS:
1501 decodeSuccess = decodeMsgStatus(bData, inStream);
1502 break;
1503 case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
1504 decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream);
1505 break;
1506 case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
1507 decodeSuccess = decodeValidityAbs(bData, inStream);
1508 break;
1509 case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
1510 decodeSuccess = decodeValidityRel(bData, inStream);
1511 break;
1512 case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
1513 decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream);
1514 break;
1515 case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
1516 decodeSuccess = decodeDeferredDeliveryRel(bData, inStream);
1517 break;
1518 case SUBPARAM_PRIVACY_INDICATOR:
1519 decodeSuccess = decodePrivacyIndicator(bData, inStream);
1520 break;
1521 case SUBPARAM_LANGUAGE_INDICATOR:
1522 decodeSuccess = decodeLanguageIndicator(bData, inStream);
1523 break;
1524 case SUBPARAM_MESSAGE_DISPLAY_MODE:
1525 decodeSuccess = decodeDisplayMode(bData, inStream);
1526 break;
1527 case SUBPARAM_PRIORITY_INDICATOR:
1528 decodeSuccess = decodePriorityIndicator(bData, inStream);
1529 break;
1530 case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
1531 decodeSuccess = decodeMsgDeliveryAlert(bData, inStream);
1532 break;
1533 case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
1534 decodeSuccess = decodeDepositIndex(bData, inStream);
1535 break;
1536 case SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA:
1537 decodeSuccess = decodeServiceCategoryProgramData(bData, inStream);
1538 break;
1539 default:
1540 decodeSuccess = decodeReserved(bData, inStream, subparamId);
1541 }
1542 if (decodeSuccess
1543 && (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER
1544 && subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
1545 foundSubparamMask |= subparamIdBit;
1546 }
1547 }
1548 if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
1549 throw runtime_error("missing MESSAGE_IDENTIFIER subparam");
1550 }
1551 if (bData->userData != nullptr) {
1552 if (isCmasAlertCategory(serviceCategory)) {
1553 decodeCmasUserData(bData, serviceCategory);
1554 } else if (bData->userData->msgEncoding
1555 == UserData::ENCODING_IS91_EXTENDED_PROTOCOL) {
1556 if ((foundSubparamMask ^ (1 << SUBPARAM_MESSAGE_IDENTIFIER)
1557 ^ (1 << SUBPARAM_USER_DATA)) != 0) {
1558// Rlog.e(LOG_TAG, "IS-91 must occur without extra subparams (" +
1559// foundSubparamMask + ")");
1560 }
1561 decodeIs91(bData);
1562 } else {
1563 decodeUserDataPayload(bData->userData, bData->hasUserDataHeader);
1564 }
1565 }
1566 return bData;
1567}
1568
1569std::string BearerData::toString() {
1570 string builder;
1571 builder.append("BearerData ");
1572 builder.append("{ messageType=" + std::to_string(messageType));
1573 builder.append(", messageId=" + std::to_string(messageId));
1574 builder.append(
1575 string(", priority=")
1576 + (priorityIndicatorSet ? std::to_string(priority) : "unset"));
1577 builder.append(
1578 string(", privacy=")
1579 + (privacyIndicatorSet ? std::to_string(privacy) : "unset"));
1580 builder.append(
1581 string(", alert=")
1582 + (alertIndicatorSet ? std::to_string(alert) : "unset"));
1583 builder.append(
1584 string(", displayMode=")
1585 + (displayModeSet ? std::to_string(displayMode) : "unset"));
1586 builder.append(
1587 string(", language=")
1588 + (languageIndicatorSet ? std::to_string(language) : "unset"));
1589 builder.append(
1590 string(", errorClass=")
1591 + (messageStatusSet ? std::to_string(errorClass) : "unset"));
1592 builder.append(
1593 string(", msgStatus=")
1594 + (messageStatusSet ? std::to_string(messageStatus) : "unset"));
1595 builder.append(
1596 string(
1597 ", msgCenterTimeStamp= unset") /*+ string (std::asctime(&msgCenterTimeStamp))*/);
1598 builder.append(
1599 string(
1600 ", validityPeriodAbsolute= unset")/* + string(std::asctime(&validityPeriodAbsolute)))*/);
1601 builder.append(
1602 string(", validityPeriodRelative= ")
1603 + ((validityPeriodRelativeSet) ?
1604 std::to_string(validityPeriodRelative) : "unset"));
1605 builder.append(
1606 string(
1607 ", deferredDeliveryTimeAbsolute= ") /*+ string(std::asctime(&deferredDeliveryTimeAbsolute))*/);
1608 builder.append(
1609 string(", deferredDeliveryTimeRelative=")
1610 + ((deferredDeliveryTimeRelativeSet) ?
1611 std::to_string(deferredDeliveryTimeRelative) : "unset"));
1612 builder.append(", userAckReq=" + std::to_string(userAckReq));
1613 builder.append(", deliveryAckReq=" + std::to_string(deliveryAckReq));
1614 builder.append(", readAckReq=" + std::to_string(readAckReq));
1615 builder.append(", reportReq=" + std::to_string(reportReq));
1616 builder.append(", numberOfMessages=" + std::to_string(numberOfMessages));
1617 builder.append(string(", callbackNumber=") + string(callbackNumber ? callbackNumber->toString() : "unset"));
1618 builder.append(", depositIndex=" + std::to_string(depositIndex));
1619 builder.append(", hasUserDataHeader=" + std::to_string(hasUserDataHeader));
1620 builder.append(
1621 ", userData=" + string(userData ? userData->toString() : "unset"));
1622 builder.append(" }");
1623 return builder;
1624}