blob: fccbfbf4dbebb182751b1c31cc827e6381ebe529 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string>
#include <memory>
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
#include "BearerData.h"
#include "UserData.h"
#include "SmsConstants.h"
#include "HexDump.h"
#include "IccUtils.h"
#include "BitwiseInputStream.h"
#include "CdmaSmsCbProgramData.h";
#include "SmsHeader.h"
#include "GsmAlphabet.h"
#include "SmsEnvelope.h"
extern "C" {
#include <glib.h>
}
BearerData::BearerData() {
// TODO Auto-generated constructor stub
}
BearerData::~BearerData() {
// TODO Auto-generated destructor stub
}
/**
* Decodes a CDMA style BCD byte like {@link #gsmBcdByteToInt}, but
* opposite nibble format. The least significant BCD digit
* is in the least significant nibble and the most significant
* is in the most significant nibble.
*/
int BearerData::cdmaBcdByteToInt(uint8_t b) {
int ret = 0;
// treat out-of-range BCD values as 0
if ((b & 0xf0) <= 0x90) {
ret = ((b >> 4) & 0xf) * 10;
}
if ((b & 0x0f) <= 0x09) {
ret += (b & 0xf);
}
return ret;
}
void BearerData::fromByteArray(std::vector<uint8_t> data, struct tm& ts) {
// C.S0015-B v2.0, 4.5.4: range is 1996-2095
int year = cdmaBcdByteToInt(data[0]);
if (year > 99 || year < 0) {
ts = {0};
return;
}
ts.tm_year = year /*>= 96 ? year + 1900 : year + 2000*/; //TBD
int month = cdmaBcdByteToInt(data[1]);
if (month < 1 || month > 12) {
ts = {0};
return;
}
ts.tm_mon = month - 1;
int day = cdmaBcdByteToInt(data[2]);
if (day < 1 || day > 31) {
ts = {0};
return;
}
ts.tm_mday = day;
int hour = cdmaBcdByteToInt(data[3]);
if (hour < 0 || hour > 23) {
ts = {0};
return;
}
ts.tm_hour = hour;
int minute = cdmaBcdByteToInt(data[4]);
if (minute < 0 || minute > 59) {
ts = {0};
return;
}
ts.tm_min = minute;
int second = cdmaBcdByteToInt(data[5]);
if (second < 0 || second > 59) {
ts = {0};
return;
}
ts.tm_sec = second;
}
void BearerData::encodeMessageId(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 3);
outStream->write(4, bData->messageType);
outStream->write(8, bData->messageId >> 8);
outStream->write(8, bData->messageId);
outStream->write(1, bData->hasUserDataHeader ? 1 : 0);
outStream->skip(3);
}
uint32_t BearerData::countAsciiSeptets(char* msg, bool force) {
string strmsg(msg);
int msgLen = strmsg.length();
if (force)
return msgLen;
for (int i = 0; i < msgLen; i++) {
if (UserData::charToAscii.find(msg[i]) == UserData::charToAscii.end()) {
return -1;
}
}
return msgLen;
}
std::vector<uint8_t> BearerData::encodeUtf16(std::string msg) {
GError *error = NULL;
gsize bytes_written = 0;
std::vector<uint8_t> data;
char *ret = g_convert (msg.c_str(), -1, "UCS-2BE", "UTF-8", NULL, &bytes_written, &error);
if (!ret) {
if (error) {
cout << "failed to convert UTF-8 to UCS-2BE character set: " << (error->code) << error->message << endl;
g_error_free (error);
}
return data;
}
for (int i = 0; i < bytes_written; i++) {
data.push_back(ret[i]);
}
g_free (ret);
return data;
}
//release byte[]
std::vector<uint8_t> BearerData::encode7bitAscii(std::string msgs, bool force) {
string msg(msgs);
shared_ptr<BitwiseOutputStream> outStream = make_shared<BitwiseOutputStream>(
msg.length());
int msgLen = msg.length();
for (int i = 0; i < msgLen; i++) {
uint8_t charCode;
try {
charCode = UserData::charToAscii.at(msg[i]);
outStream->write(7, charCode);
} catch (const out_of_range &e) {
if (force) {
outStream->write(7, UserData::UNENCODABLE_7_BIT_CHAR);
}
//TBD log
}
}
return outStream->toByteVector();
}
BearerData::Gsm7bitCodingResult BearerData::encode7bitGsm(std::string msg, int septetOffset, bool force) {
std::vector<uint8_t> fullData = GsmAlphabet::stringToGsm7BitPacked(msg, septetOffset, !force, 0, 0);
Gsm7bitCodingResult result;
result.data.insert(result.data.begin(), fullData.begin() + 1, fullData.end());
result.septets = fullData[0] & 0x00FF;
return result;
}
void BearerData::encode7bitEms(std::shared_ptr<UserData> uData, std::vector<uint8_t> udhData, bool force) {
int udhBytes = udhData.size() + 1; // Add length octet.
int udhSeptets = ((udhBytes * 8) + 6) / 7;
BearerData::Gsm7bitCodingResult gcr = encode7bitGsm(uData->payloadStr, udhSeptets, force);
uData->msgEncoding = UserData::ENCODING_GSM_7BIT_ALPHABET;
uData->msgEncodingSet = true;
uData->numFields = gcr.septets;
uData->payload = gcr.data;
uData->payload.insert(uData->payload.begin()+1, udhData.begin(), udhData.end());
uData->payload[0] = (uint8_t)udhData.size();
}
void BearerData::encode16bitEms(std::shared_ptr<UserData> uData, std::vector<uint8_t> udhData) {
std::vector<uint8_t> payload = encodeUtf16(uData->payloadStr);
int udhBytes = udhData.size() + 1; // Add length octet.
int udhCodeUnits = (udhBytes + 1) / 2;
int payloadCodeUnits = payload.size() / 2;
uData->msgEncoding = UserData::ENCODING_UNICODE_16;
uData->msgEncodingSet = true;
uData->numFields = udhCodeUnits + payloadCodeUnits;
uData->payload.push_back(udhData.size());
(uData->payload).insert((uData->payload).begin() + 1, udhData.begin(), udhData.end());
(uData->payload).insert((uData->payload).begin() + udhBytes, payload.begin(), payload.end());
}
void BearerData::encodeOctetEms(std::shared_ptr<UserData> uData, std::vector<uint8_t> udhData) {
int udhBytes = udhData.size() + 1;
uData->msgEncoding = UserData::ENCODING_OCTET;
uData->msgEncodingSet = true;
uData->numFields = udhBytes + uData->payload.size();
//byte[] payload = new byte[uData.numFields];
std::vector<uint8_t> payload;
uData->payload.push_back(udhData.size());
(uData->payload).insert((uData->payload).begin() + 1, udhData.begin(), udhData.end());
(uData->payload).insert((uData->payload).begin() + udhBytes, payload.begin(), payload.end());
}
void BearerData::encodeEmsUserDataPayload(std::shared_ptr<UserData> uData) {
std::vector<uint8_t> headerData = SmsHeader::toByteArray(uData->userDataHeader);
if (uData->msgEncodingSet) {
if (uData->msgEncoding == UserData::ENCODING_GSM_7BIT_ALPHABET) {
encode7bitEms(uData, headerData, true);
} else if (uData->msgEncoding == UserData::ENCODING_OCTET) {
encodeOctetEms(uData, headerData);
} else if (uData->msgEncoding == UserData::ENCODING_UNICODE_16) {
encode16bitEms(uData, headerData);
} else {
cout << "unsupported EMS user data encoding (" << uData->msgEncoding << ")" <<endl;
}
} else {
encode7bitEms(uData, headerData, false);
}
}
//maybe free memory
void BearerData::encodeUserDataPayload(std::shared_ptr<UserData> uData) {
if ((uData->payloadStr.empty())
&& (uData->msgEncoding != UserData::ENCODING_OCTET)) {
//Rlog.e(LOG_TAG, "user data with null payloadStr");
uData->payloadStr = string("");
}
if (uData->userDataHeader != nullptr) {
encodeEmsUserDataPayload(uData);
return;
}
if (uData->msgEncodingSet) {
if (uData->msgEncoding == UserData::ENCODING_OCTET) {
if (uData->payload.empty()) {
//Rlog.e(LOG_TAG, "user data with octet encoding but null payload");
uData->payload.clear();
uData->numFields = 0;
} else {
uData->numFields = uData->payload.size(); //maybe wrong?
}
} else {
if (uData->payloadStr.empty()) {
//Rlog.e(LOG_TAG, "non-octet user data with null payloadStr");
uData->payloadStr = string("");
}
// if (uData.msgEncoding == UserData::ENCODING_GSM_7BIT_ALPHABET) {
// Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true);
// uData.payload = gcr.data;
// uData.numFields = gcr.septets;
// } else
if (uData->msgEncoding == UserData::ENCODING_7BIT_ASCII) {
uData->payload = encode7bitAscii(uData->payloadStr, true);
uData->numFields = uData->payloadStr.size();
} else if (uData->msgEncoding == UserData::ENCODING_UNICODE_16) {
uData->payload = encodeUtf16(uData->payloadStr);
uData->numFields = string(uData->payloadStr).length();
// } else if (uData->msgEncoding == UserData::ENCODING_SHIFT_JIS) {
// uData->payload = encodeShiftJis(uData->payloadStr);
// uData->numFields = string(uData->payloadStr).length();
} else {
cout << "unsupported user data encoding (" << uData->msgEncoding << ")"
<< endl;
}
}
} else {
uData->payload = encode7bitAscii(uData->payloadStr, false);
string str1 = HexDump::toHexString(uData->payload);
//std::cout << "uData->payload: " << str1 << endl;
uData->msgEncoding = UserData::ENCODING_7BIT_ASCII;
// try {
// } catch (CodingException ex) {
// uData.payload = encodeUtf16(uData.payloadStr);
// uData.msgEncoding = UserData.ENCODING_UNICODE_16;
// }
uData->numFields = uData->payloadStr.size();
uData->msgEncodingSet = true;
}
}
void BearerData::encodeUserData(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
/*
* TODO(cleanup): Do we really need to set userData.payload as
* a side effect of encoding? If not, we could avoid data
* copies by passing outStream directly.
*/
encodeUserDataPayload(bData->userData);
bData->hasUserDataHeader = false; //bData->userData->userDataHeader != null;
int length = bData->userData->payload.size();
if (length > SmsConstants::MAX_USER_DATA_BYTES) {
cout << "encoded user data too large (" << bData->userData->payload.size()
<< " > " << SmsConstants::MAX_USER_DATA_BYTES << " bytes)" << endl;
return;
}
/*
* TODO(cleanup): figure out what the right answer is WRT paddingBits field
*
* userData->pad->ingBits = (userData->payload.length * 8) - (userData.numFields * 7);
* userData.paddingBits = 0; // XXX this seems better, but why?
*
*/
int dataBits = (length * 8) - (bData->userData->paddingBits);
int paramBits = dataBits + 13;
if (((bData->userData->msgEncoding)
== UserData::ENCODING_IS91_EXTENDED_PROTOCOL)
|| ((bData->userData->msgEncoding) == UserData::ENCODING_GSM_DCS)) {
paramBits += 8;
}
int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
int paddingBits = (paramBytes * 8) - paramBits;
outStream->write(8, paramBytes);
outStream->write(5, bData->userData->msgEncoding);
if ((bData->userData->msgEncoding == UserData::ENCODING_IS91_EXTENDED_PROTOCOL)
|| (bData->userData->msgEncoding == UserData::ENCODING_GSM_DCS)) {
outStream->write(8, bData->userData->msgType);
}
outStream->write(8, (bData->userData)->numFields);
outStream->writeByteVector(dataBits, (bData->userData)->payload);
if (paddingBits > 0)
outStream->write(paddingBits, 0);
}
void BearerData::encodeReplyOption(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(1, bData->userAckReq ? 1 : 0);
outStream->write(1, bData->deliveryAckReq ? 1 : 0);
outStream->write(1, bData->readAckReq ? 1 : 0);
outStream->write(1, bData->reportReq ? 1 : 0);
outStream->write(4, 0);
}
//free memory
std::vector<uint8_t> BearerData::encodeDtmfSmsAddress(std::string address) {
int digits = address.length();
int dataBits = digits * 4;
int dataBytes = (dataBits / 8);
dataBytes += (dataBits % 8) > 0 ? 1 : 0;
//uint8_t* rawData = new uint8_t[dataBytes];
std::vector<uint8_t> rawData;
for (int i = 0; i < digits; i++) {
char c = address[i];
int val = 0;
if ((c >= '1') && (c <= '9'))
val = c - '0';
else if (c == '0')
val = 10;
else if (c == '*')
val = 11;
else if (c == '#')
val = 12;
else
return rawData;
int size = rawData.size();
if ((i / 2) < size) {
rawData[i / 2] |= val << (4 - ((i % 2) * 4));
} else {
rawData.push_back(val << (4 - ((i % 2) * 4)));
}
}
return rawData;
}
void BearerData::encodeCdmaSmsAddress(std::shared_ptr<CdmaSmsAddress> addr) {
if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
//TBD
// try {
// addr.origBytes = addr.address.getBytes("US-ASCII");
// } catch (java.io.UnsupportedEncodingException ex) {
// throw new CodingException("invalid SMS address, cannot convert to ASCII");
// }
} else {
addr->origBytes = encodeDtmfSmsAddress(addr->address);
}
}
void BearerData::encodeCallbackNumber(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
auto addr = bData->callbackNumber;
encodeCdmaSmsAddress(addr);
int paramBits = 9;
int dataBits = 0;
if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
paramBits += 7;
dataBits = addr->numberOfDigits * 8;
} else {
dataBits = addr->numberOfDigits * 4;
}
paramBits += dataBits;
int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
int paddingBits = (paramBytes * 8) - paramBits;
outStream->write(8, paramBytes);
outStream->write(1, addr->digitMode);
if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
outStream->write(3, addr->ton);
outStream->write(4, addr->numberPlan);
}
outStream->write(8, addr->numberOfDigits);
outStream->writeByteVector(dataBits, addr->origBytes);
if (paddingBits > 0)
outStream->write(paddingBits, 0);
}
void BearerData::encodeMsgStatus(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(2, bData->errorClass);
outStream->write(6, bData->messageStatus);
}
void BearerData::encodeMsgCount(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(8, bData->numberOfMessages);
}
void BearerData::encodeValidityPeriodRel(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(8, bData->validityPeriodRelative);
}
void BearerData::encodePrivacyIndicator(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(2, bData->privacy);
outStream->skip(6);
}
void BearerData::encodeLanguageIndicator(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(8, bData->language);
}
void BearerData::encodeDisplayMode(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(2, bData->displayMode);
outStream->skip(6);
}
void BearerData::encodePriorityIndicator(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(2, bData->priority);
outStream->skip(6);
}
void BearerData::encodeMsgDeliveryAlert(BearerData* bData,
shared_ptr<BitwiseOutputStream> outStream) {
outStream->write(8, 1);
outStream->write(2, bData->alert);
outStream->skip(6);
}
std::vector<uint8_t> BearerData::encode(BearerData* bData) {
bData->hasUserDataHeader = false; //((bData->userData != nullptr) && (bData->userData->userDataHeader != null));
shared_ptr<BitwiseOutputStream> outStream = make_shared<BitwiseOutputStream>(
200);
outStream->write(8, SUBPARAM_MESSAGE_IDENTIFIER);
encodeMessageId(bData, outStream);
if (bData->userData != nullptr) {
outStream->write(8, SUBPARAM_USER_DATA);
encodeUserData(bData, outStream);
//cout << "userData" << endl;
}
if (bData->callbackNumber != nullptr) {
//cout << "callbackNumber" << endl;
outStream->write(8, SUBPARAM_CALLBACK_NUMBER);
encodeCallbackNumber(bData, outStream);
}
if (bData->userAckReq || bData->deliveryAckReq || bData->readAckReq
|| bData->reportReq) {
//cout << "userAckReq" << endl;
outStream->write(8, SUBPARAM_REPLY_OPTION);
encodeReplyOption(bData, outStream);
}
if (bData->numberOfMessages != 0) {
//cout << "numberOfMessages" << endl;
outStream->write(8, SUBPARAM_NUMBER_OF_MESSAGES);
encodeMsgCount(bData, outStream);
}
if (bData->validityPeriodRelativeSet) {
//cout << "validityPeriodRelativeSet" << endl;
outStream->write(8, SUBPARAM_VALIDITY_PERIOD_RELATIVE);
encodeValidityPeriodRel(bData, outStream);
}
if (bData->privacyIndicatorSet) {
//cout << "privacyIndicatorSet" << endl;
outStream->write(8, SUBPARAM_PRIVACY_INDICATOR);
encodePrivacyIndicator(bData, outStream);
}
if (bData->languageIndicatorSet) {
//cout << "languageIndicatorSet" << endl;
outStream->write(8, SUBPARAM_LANGUAGE_INDICATOR);
encodeLanguageIndicator(bData, outStream);
}
if (bData->displayModeSet) {
//cout << "displayModeSet" << endl;
outStream->write(8, SUBPARAM_MESSAGE_DISPLAY_MODE);
encodeDisplayMode(bData, outStream);
}
if (bData->priorityIndicatorSet) {
//cout << "priorityIndicatorSet" << endl;
outStream->write(8, SUBPARAM_PRIORITY_INDICATOR);
encodePriorityIndicator(bData, outStream);
}
if (bData->alertIndicatorSet) {
//cout << "alertIndicatorSet" << endl;
outStream->write(8, SUBPARAM_ALERT_ON_MESSAGE_DELIVERY);
encodeMsgDeliveryAlert(bData, outStream);
}
if (bData->messageStatusSet) {
//cout << "messageStatusSet" << endl;
outStream->write(8, SUBPARAM_MESSAGE_STATUS);
encodeMsgStatus(bData, outStream);
}
// if (bData->serviceCategoryProgramResults != null) {
// outStream->write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS);
// encodeScpResults(bData, outStream);
// }
return outStream->toByteVector();
}
std::shared_ptr<BearerData> BearerData::decode(std::vector<uint8_t> smsData) {
return decode(smsData, 0);
}
bool BearerData::decodeMessageId(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 3 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->messageType = inStream->read(4);
bData->messageId = inStream->read(8) << 8;
bData->messageId |= inStream->read(8);
bData->hasUserDataHeader = (inStream->read(1) == 1);
inStream->skip(3);
}
if ((!decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
}
inStream->skip(paramBits);
return decodeSuccess;
}
bool BearerData::decodeUserData(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
uint32_t paramBits = inStream->read((uint32_t) 8) * 8;
bData->userData = std::make_shared<UserData>();
bData->userData->msgEncoding = inStream->read(5);
bData->userData->msgEncodingSet = true;
bData->userData->msgType = 0;
int consumedBits = 5;
if ((bData->userData->msgEncoding == UserData::ENCODING_IS91_EXTENDED_PROTOCOL)
|| (bData->userData->msgEncoding == UserData::ENCODING_GSM_DCS)) {
bData->userData->msgType = inStream->read(8);
consumedBits += 8;
}
bData->userData->numFields = inStream->read(8);
consumedBits += 8;
int dataBits = paramBits - consumedBits;
bData->userData->payload = inStream->readByteVector(dataBits);
return true;
}
bool BearerData::decodeUserResponseCode(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const uint32_t EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
uint32_t paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->userResponseCode = inStream->read(8);
}
if ((!decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "USER_RESPONSE_CODE decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
}
inStream->skip(paramBits);
bData->userResponseCodeSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodeReplyOption(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->userAckReq = (inStream->read(1) == 1);
bData->deliveryAckReq = (inStream->read(1) == 1);
bData->readAckReq = (inStream->read(1) == 1);
bData->reportReq = (inStream->read(1) == 1);
inStream->skip(4);
}
if ((!decodeSuccess) || (paramBits > 0)) {
// Rlog->d(LOG_TAG, "REPLY_OPTION decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
}
inStream->skip(paramBits);
return decodeSuccess;
}
bool BearerData::decodeMsgCount(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->numberOfMessages = IccUtils::cdmaBcdByteToInt(
(uint8_t) inStream->read(8));
}
if ((!decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
}
inStream->skip(paramBits);
return decodeSuccess;
}
std::string BearerData::decodeDtmfSmsAddress(std::vector<uint8_t> rawData,
int numFields) {
/* DTMF 4-bit digit encoding, defined in at
* 3GPP2 C.S005-D, v2.0, table 2.7.1.3.2.4-4 */
string strBuf;
for (int i = 0; i < numFields; i++) {
int val = 0x0F & (rawData[i / 2] >> (4 - ((i % 2) * 4)));
if ((val >= 1) && (val <= 9))
strBuf.append(to_string(val));
else if (val == 10)
strBuf.push_back('0');
else if (val == 11)
strBuf.push_back('*');
else if (val == 12)
strBuf.push_back('#');
else
throw runtime_error(
"invalid SMS address DTMF code (" + std::to_string(val) + ")");
}
return strBuf;
}
void BearerData::decodeSmsAddress(std::shared_ptr<CdmaSmsAddress> addr) {
if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
//android not support
// try {
// /* As specified in 3GPP2 C.S0015-B, v2, 4.5.15 -- actually
// * just 7-bit ASCII encoding, with the MSB being zero. */
// addr->address = new string(addr->origBytes, addr->origBytes_length);
// } catch (exception& ex) {
// throw runtime_error("invalid SMS address ASCII code");
// }
} else {
addr->address = decodeDtmfSmsAddress(addr->origBytes, addr->numberOfDigits);
}
}
bool BearerData::decodeCallbackNumber(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8; //at least
int paramBits = inStream->read(8) * 8;
if (paramBits < EXPECTED_PARAM_SIZE) {
inStream->skip(paramBits);
return false;
}
std::shared_ptr<CdmaSmsAddress> addr = make_shared<CdmaSmsAddress>();
addr->digitMode = inStream->read(1);
uint8_t fieldBits = 4;
uint8_t consumedBits = 1;
if (addr->digitMode == CdmaSmsAddress::DIGIT_MODE_8BIT_CHAR) {
addr->ton = inStream->read(3);
addr->numberPlan = inStream->read(4);
fieldBits = 8;
consumedBits += 7;
}
addr->numberOfDigits = inStream->read(8);
consumedBits += 8;
int remainingBits = paramBits - consumedBits;
int dataBits = addr->numberOfDigits * fieldBits;
int paddingBits = remainingBits - dataBits;
if (remainingBits < dataBits) {
throw runtime_error(
string("CALLBACK_NUMBER subparam encoding size error (")
+ string("remainingBits + ") + std::to_string(remainingBits)
+ string(", dataBits + ") + std::to_string(dataBits)
+ string(", paddingBits + ") + std::to_string(paddingBits)
+ string(")"));
}
addr->origBytes = inStream->readByteVector(dataBits);
inStream->skip(paddingBits);
decodeSmsAddress(addr);
bData->callbackNumber = addr;
return true;
}
bool BearerData::decodeMsgStatus(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->errorClass = inStream->read(2);
bData->messageStatus = inStream->read(6);
}
if ((!decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "MESSAGE_STATUS decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
}
inStream->skip(paramBits);
bData->messageStatusSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodeMsgCenterTimeStamp(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 6 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
fromByteArray(inStream->readByteVector(6 * 8), bData->msgCenterTimeStamp);
}
if ((!decodeSuccess) || (paramBits > 0)) {
/* Rlog.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");*/
}
inStream->skip(paramBits);
return decodeSuccess;
}
bool BearerData::decodeValidityAbs(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 6 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
fromByteArray(inStream->readByteVector(6 * 8),
bData->validityPeriodAbsolute);
}
if ((!decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
}
inStream->skip(paramBits);
return decodeSuccess;
}
bool BearerData::decodeValidityRel(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
//bData->deferredDeliveryTimeRelative = inStream->read(8);
bData->validityPeriodRelative = inStream->read(8);
}
if ((!decodeSuccess) || (paramBits > 0)) {
/* Rlog.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");*/
}
inStream->skip(paramBits);
//bData->deferredDeliveryTimeRelativeSet = decodeSuccess;
bData->validityPeriodRelativeSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodeDeferredDeliveryAbs(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 6 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
fromByteArray(inStream->readByteVector(6 * 8),
bData->deferredDeliveryTimeAbsolute);
}
if ((!decodeSuccess) || (paramBits > 0)) {
/* Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");*/
}
inStream->skip(paramBits);
return decodeSuccess;
}
bool BearerData::decodeDeferredDeliveryRel(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
//bData->validityPeriodRelative = inStream->read(8);
bData->deferredDeliveryTimeRelative = inStream->read(8);
}
if ((!decodeSuccess) || (paramBits > 0)) {
/* Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");*/
}
inStream->skip(paramBits);
//bData->validityPeriodRelativeSet = decodeSuccess;
bData->deferredDeliveryTimeRelativeSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodePrivacyIndicator(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->privacy = inStream->read(2);
inStream->skip(6);
}
if ((!decodeSuccess) || (paramBits > 0)) {
/* Rlog.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");*/
}
inStream->skip(paramBits);
bData->privacyIndicatorSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodeLanguageIndicator(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->language = inStream->read(8);
}
if ((!decodeSuccess) || (paramBits > 0)) {
/* Rlog.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");*/
}
inStream->skip(paramBits);
bData->languageIndicatorSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodeDisplayMode(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->displayMode = inStream->read(2);
inStream->skip(6);
}
// if ((! decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "DISPLAY_MODE decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
// }
inStream->skip(paramBits);
bData->displayModeSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodePriorityIndicator(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->priority = inStream->read(2);
inStream->skip(6);
}
// if ((! decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
// }
inStream->skip(paramBits);
bData->priorityIndicatorSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodeMsgDeliveryAlert(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 1 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->alert = inStream->read(2);
inStream->skip(6);
}
if ((!decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ")");
}
inStream->skip(paramBits);
bData->alertIndicatorSet = decodeSuccess;
return decodeSuccess;
}
bool BearerData::decodeDepositIndex(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
const int EXPECTED_PARAM_SIZE = 2 * 8;
bool decodeSuccess = false;
int paramBits = inStream->read(8) * 8;
if (paramBits >= EXPECTED_PARAM_SIZE) {
paramBits -= EXPECTED_PARAM_SIZE;
decodeSuccess = true;
bData->depositIndex = (inStream->read(8) << 8) | inStream->read(8);
}
/* if ((! decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
}*/
inStream->skip(paramBits);
return decodeSuccess;
}
int BearerData::getBitsForNumFields(int msgEncoding, int numFields) {
switch (msgEncoding) {
case UserData::ENCODING_OCTET:
case UserData::ENCODING_SHIFT_JIS:
case UserData::ENCODING_KOREAN:
case UserData::ENCODING_LATIN:
case UserData::ENCODING_LATIN_HEBREW:
return numFields * 8;
case UserData::ENCODING_IA5:
case UserData::ENCODING_7BIT_ASCII:
case UserData::ENCODING_GSM_7BIT_ALPHABET:
return numFields * 7;
case UserData::ENCODING_UNICODE_16:
return numFields * 16;
default:
throw runtime_error("unsupported message encoding (" + msgEncoding + ')');
}
}
std::string BearerData::decodeUtf8(std::vector<uint8_t> data, int offset, int numFields)
{
std::string str;
for (int i = offset; i < (offset + numFields); i++)
{
str.push_back((char)data[i]);
}
return str;
}
std::string BearerData::decodeLatin(std::vector<uint8_t> data, int offset, int numFields)
{
std::string str;
for (int i = offset; i < (offset + numFields); i++)
{
str.push_back(data[i]);
}
char* text = g_convert (str.c_str(), numFields, "UTF-8", "ISO−8859−1", NULL, NULL, NULL);
if(!text) {
printf("convert (Latin) result is null\n");
return std::string("");
}
std::string ret(text);
g_free(text);
return ret;
}
std::string BearerData::decodeUtf16(std::vector<uint8_t> data, int offset, int numFields)
{
std::string str;
for (int i = offset; i < (offset + numFields*2); i++)
{
str.push_back((char)data[i]);
}
char* text = g_convert (str.c_str(), numFields*2, "UTF-8", "UCS-2BE", NULL, NULL, NULL);
if(!text) {
printf("convert (Utf16) result is null\n");
return std::string("");
}
std::string ret(text);
g_free(text);
text = NULL;
return ret;
}
std::string BearerData::decode7bitAscii(std::vector<uint8_t> data, int offset,
int numFields) {
int headerSeptets = (offset * 8 + 6) / 7;
numFields -= headerSeptets;
std::string strBuf;
auto inStream = std::make_shared<BitwiseInputStream>(data);
int wantedBits = (headerSeptets + numFields) * 7;
if (inStream->available() < wantedBits) {
throw runtime_error(
"insufficient data (wanted " + std::to_string(wantedBits)
+ " bits, but only have " + std::to_string(inStream->available())
+ ")");
}
inStream->skip(headerSeptets * 7);
for (int i = 0; i < numFields; i++) {
int charCode = inStream->read(7);
if ((charCode >= UserData::ASCII_MAP_BASE_INDEX)
&& (charCode <= UserData::ASCII_MAP_MAX_INDEX)) {
strBuf.push_back(
UserData::ASCII_MAP[charCode - UserData::ASCII_MAP_BASE_INDEX]);
} else if (charCode == UserData::ASCII_NL_INDEX) {
strBuf.push_back('\n');
} else if (charCode == UserData::ASCII_CR_INDEX) {
strBuf.push_back('\r');
} else {
/* For other charCodes, they are unprintable, and so simply use SPACE. */
strBuf.push_back(' ');
}
}
return strBuf;
}
std::string BearerData::decode7bitGsm(std::vector<uint8_t> data, int offset,
int numFields) {
// Start reading from the next 7-bit aligned boundary after offset.
int offsetBits = offset * 8;
int offsetSeptets = (offsetBits + 6) / 7;
numFields -= offsetSeptets;
int paddingBits = (offsetSeptets * 7) - offsetBits;
string result = GsmAlphabet::gsm7BitPackedToString(data, offset, numFields,
paddingBits, 0, 0);
if (result.empty()) {
throw runtime_error("7bit GSM decoding failed");
}
return result;
}
std::string BearerData::decodeGsmDcs(std::vector<uint8_t> data, int offset,
int numFields, int msgType) {
if ((msgType & 0xC0) != 0) {
throw runtime_error(
"unsupported coding group (" + std::to_string(msgType) + ")");
}
switch ((msgType >> 2) & 0x3) {
case UserData::ENCODING_GSM_DCS_7BIT:
return decode7bitGsm(data, offset, numFields);
// case UserData.ENCODING_GSM_DCS_8BIT:
// return decodeUtf8(data, offset, numFields);
// case UserData.ENCODING_GSM_DCS_16BIT:
// return decodeUtf16(data, offset, numFields);
default:
throw runtime_error(
"unsupported user msgType encoding (" + std::to_string(msgType) + ")");
}
}
void BearerData::decodeUserDataPayload(std::shared_ptr<UserData> userData,
bool hasUserDataHeader) {
int offset = 0;
//printf("1st,%s\n",userData->toString().c_str());
if (hasUserDataHeader) {
int udhLen = userData->payload[0] & 0x00FF;
offset += udhLen + 1;
/* byte[] headerData = new byte[udhLen];
System.arraycopy(userData.payload, 1, headerData, 0, udhLen)*/;
std::vector<uint8_t> v;
v.insert(v.end(), userData->payload.begin() + 1,
userData->payload.begin() + udhLen);
userData->userDataHeader = SmsHeader::fromByteArray(v);
//for test cdma long sms, SmsHeader::fromByteArray get the sequence number,but it will always be the last sequence,
//maybe overwriten by the last sms part. we print here directly as a temporary solution.
if(udhLen == 5 && (userData->payload[1] & 0x00FF)==0x00)//0x00 is the concatenated SMS id
{
printf("udhLen=%d,refNumber=%d,msgCount=%d, seqNumber=%d\n", udhLen,
userData->payload[3] & 0x00FF,userData->payload[4] & 0x00FF,userData->payload[5] & 0x00FF);
}
else{
printf("udhLen=%d, not for test format!\n",udhLen);
}
}
//add for long sms test begin
//printf("offset: %d\n",offset);
//printf("2nd,%s\n",userData->toString().c_str());
//add for long sms test end
switch (userData->msgEncoding) {
case UserData::ENCODING_OCTET: {
/*
* Octet decoding depends on the carrier service.
*/
bool decodingtypeUTF8 = true;
// Strip off any padding bytes, meaning any differences between the length of the
// array and the target length specified by numFields. This is to avoid any
// confusion by code elsewhere that only considers the payload array length.
int copyLen = userData->numFields < userData->payload.size() ? userData->numFields : userData->payload.size();
std::vector<uint8_t> payload;
payload.insert(payload.end(), userData->payload.begin(), userData->payload.begin() + copyLen);
userData->payload = payload;
if (!decodingtypeUTF8) {
// There are many devices in the market that send 8bit text sms (latin encoded) as
// octet encoded.
userData->payloadStr = decodeLatin(userData->payload, offset, userData->numFields);
} else {
userData->payloadStr = decodeUtf8(userData->payload, offset, userData->numFields);
}
break;
}
case UserData::ENCODING_IA5:
case UserData::ENCODING_7BIT_ASCII: {
userData->payloadStr = decode7bitAscii(userData->payload, offset, userData->numFields);
break;
case UserData::ENCODING_UNICODE_16:
userData->payloadStr = decodeUtf16(userData->payload, offset, userData->numFields);
break;
}
case UserData::ENCODING_GSM_7BIT_ALPHABET: {
userData->payloadStr = decode7bitGsm(userData->payload, offset, userData->numFields);
break;
}
case UserData::ENCODING_LATIN:
userData->payloadStr = decodeLatin(userData->payload, offset, userData->numFields);
break;
// case UserData::ENCODING_SHIFT_JIS:
// // userData->payloadStr = decodeShiftJis(userData->payload, offset, userData->numFields);
// //TBD "unsupported user data encoding"
// break;
case UserData::ENCODING_GSM_DCS: {
userData->payloadStr = decodeGsmDcs(userData->payload, offset,
userData->numFields, userData->msgType);
break;
}
default:
printf("unsupported user data encoding : %\n" ,std::to_string(userData->msgEncoding));
// throw runtime_error(
// "unsupported user data encoding ("
// + std::to_string(userData->msgEncoding) + ")");
}
}
bool BearerData::decodeServiceCategoryProgramData(
std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream) {
if (inStream->available() < 13) {
throw runtime_error(
string("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only ")
+ std::to_string(inStream->available())
+ string(" bits available"));
}
int paramBits = inStream->read(8) * 8;
int msgEncoding = inStream->read(5);
paramBits -= 5;
if (inStream->available() < paramBits) {
throw runtime_error(
string("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only ")
+ std::to_string(inStream->available())
+ string(" bits available (") + std::to_string(paramBits)
+ string(" bits expected)"));
}
auto programDataList = make_shared<list<shared_ptr<CdmaSmsCbProgramData>>>();
const int CATEGORY_FIELD_MIN_SIZE = 6 * 8;
bool decodeSuccess = false;
while (paramBits >= CATEGORY_FIELD_MIN_SIZE) {
int operation = inStream->read(4);
int category = (inStream->read(8) << 8) | inStream->read(8);
int language = inStream->read(8);
int maxMessages = inStream->read(8);
int alertOption = inStream->read(4);
int numFields = inStream->read(8);
paramBits -= CATEGORY_FIELD_MIN_SIZE;
int textBits = getBitsForNumFields(msgEncoding, numFields);
if (paramBits < textBits) {
throw runtime_error(
string("category name is ") + std::to_string(textBits)
+ string(" bits in length,") + string(" but there are only ")
+ std::to_string(paramBits) + string(" bits available"));
}
auto userData = make_shared<UserData>();
userData->msgEncoding = msgEncoding;
userData->msgEncodingSet = true;
userData->numFields = numFields;
userData->payload = inStream->readByteVector(textBits);
paramBits -= textBits;
decodeUserDataPayload(userData, false);
string categoryName = userData->payloadStr;
auto programData = std::make_shared<CdmaSmsCbProgramData>(operation,
category, language, maxMessages, alertOption, categoryName);
programDataList->push_back(programData);
decodeSuccess = true;
}
if ((!decodeSuccess) || (paramBits > 0)) {
// Rlog.d(LOG_TAG, "SERVICE_CATEGORY_PROGRAM_DATA decode " +
// (decodeSuccess ? "succeeded" : "failed") +
// " (extra bits = " + paramBits + ')');
}
inStream->skip(paramBits);
bData->serviceCategoryProgramData = programDataList;
return decodeSuccess;
}
bool BearerData::decodeReserved(std::shared_ptr<BearerData> bData,
std::shared_ptr<BitwiseInputStream> inStream, int subparamId) {
bool decodeSuccess = false;
int subparamLen = inStream->read(8); // SUBPARAM_LEN
int paramBits = subparamLen * 8;
if (paramBits <= inStream->available()) {
decodeSuccess = true;
inStream->skip(paramBits);
}
// Rlog.d(LOG_TAG, "RESERVED bearer data subparameter " + subparamId + " decode "
// + (decodeSuccess ? "succeeded" : "failed") + " (param bits = " + paramBits + ")");
if (!decodeSuccess) {
throw runtime_error(
"RESERVED bearer data subparameter " + std::to_string(subparamId)
+ " had invalid SUBPARAM_LEN " + std::to_string(subparamLen));
}
return decodeSuccess;
}
bool BearerData::isCmasAlertCategory(int category) {
return category >= SmsEnvelope::SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT
&& category <= SmsEnvelope::SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE;
}
int BearerData::serviceCategoryToCmasMessageClass(int serviceCategory) {
switch (serviceCategory) {
case SmsEnvelope::SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT:
return SmsCbCmasInfo::CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT;
case SmsEnvelope::SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
return SmsCbCmasInfo::CMAS_CLASS_EXTREME_THREAT;
case SmsEnvelope::SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
return SmsCbCmasInfo::CMAS_CLASS_SEVERE_THREAT;
case SmsEnvelope::SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
return SmsCbCmasInfo::CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY;
case SmsEnvelope::SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
return SmsCbCmasInfo::CMAS_CLASS_REQUIRED_MONTHLY_TEST;
default:
return SmsCbCmasInfo::CMAS_CLASS_UNKNOWN;
}
}
void BearerData::decodeCmasUserData(std::shared_ptr<BearerData> bData,
int serviceCategory) {
//uint8_t array[bData->userData->payload.size()];
//std::copy(bData->userData->payload.begin(), bData->userData->payload.end(), array);
auto inStream = make_shared<BitwiseInputStream>(bData->userData->payload);
if (inStream->available() < 8) {
throw runtime_error("emergency CB with no CMAE_protocol_version");
}
int protocolVersion = inStream->read(8);
if (protocolVersion != 0) {
throw runtime_error("unsupported CMAE_protocol_version " + protocolVersion);
}
int messageClass = serviceCategoryToCmasMessageClass(serviceCategory);
int category = SmsCbCmasInfo::CMAS_CATEGORY_UNKNOWN;
int responseType = SmsCbCmasInfo::CMAS_RESPONSE_TYPE_UNKNOWN;
int severity = SmsCbCmasInfo::CMAS_SEVERITY_UNKNOWN;
int urgency = SmsCbCmasInfo::CMAS_URGENCY_UNKNOWN;
int certainty = SmsCbCmasInfo::CMAS_CERTAINTY_UNKNOWN;
while (inStream->available() >= 16) {
int recordType = inStream->read(8);
int recordLen = inStream->read(8);
switch (recordType) {
case 0: // Type 0 elements (Alert text)
{
auto alertUserData = make_shared<UserData>();
alertUserData->msgEncoding = inStream->read(5);
alertUserData->msgEncodingSet = true;
alertUserData->msgType = 0;
int numFields; // number of chars to decode
switch (alertUserData->msgEncoding) {
case UserData::ENCODING_OCTET:
case UserData::ENCODING_LATIN:
numFields = recordLen - 1; // subtract 1 byte for encoding
break;
case UserData::ENCODING_IA5:
case UserData::ENCODING_7BIT_ASCII:
case UserData::ENCODING_GSM_7BIT_ALPHABET:
numFields = ((recordLen * 8) - 5) / 7; // subtract 5 bits for encoding
break;
case UserData::ENCODING_UNICODE_16:
numFields = (recordLen - 1) / 2;
break;
default:
numFields = 0; // unsupported encoding
}
alertUserData->numFields = numFields;
alertUserData->payload = inStream->readByteVector(recordLen * 8 - 5);
decodeUserDataPayload(alertUserData, false);
bData->userData = alertUserData;
break;
}
case 1: // Type 1 elements
{
category = inStream->read(8);
responseType = inStream->read(8);
severity = inStream->read(4);
urgency = inStream->read(4);
certainty = inStream->read(4);
inStream->skip(recordLen * 8 - 28);
break;
}
default:
//Rlog.w(LOG_TAG, "skipping unsupported CMAS record type " + recordType);
inStream->skip(recordLen * 8);
break;
}
}
bData->cmasWarningInfo = make_shared<SmsCbCmasInfo>(messageClass, category,
responseType, severity, urgency, certainty);
}
void BearerData::decodeIs91VoicemailStatus(std::shared_ptr<BearerData> bData) {
//uint8_t array[bData->userData->payload.size()];
//std::copy(bData->userData->payload.begin(), bData->userData->payload.end(), array);
auto inStream = make_shared<BitwiseInputStream>(bData->userData->payload);
int dataLen = inStream->available() / 6; // 6-bit packed character encoding.
int numFields = bData->userData->numFields;
if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
throw runtime_error("IS-91 voicemail status decoding failed");
}
string strbuf;
while (inStream->available() >= 6) {
strbuf.push_back(UserData::ASCII_MAP[inStream->read(6)]);
}
string data = strbuf;
bData->numberOfMessages = std::stoi(data.substr(0, 2));
char prioCode = data.at(2);
if (prioCode == ' ') {
bData->priority = PRIORITY_NORMAL;
} else if (prioCode == '!') {
bData->priority = PRIORITY_URGENT;
} else {
throw runtime_error(
string("IS-91 voicemail status decoding failed: ")
+ string("illegal priority setting (") + std::to_string(prioCode)
+ string(")"));
}
bData->priorityIndicatorSet = true;
bData->userData->payloadStr = data.substr(3, numFields - 6);
}
void BearerData::decodeIs91Cli(std::shared_ptr<BearerData> bData) {
//uint8_t array[bData->userData->payload.size()];
//std::copy(bData->userData->payload.begin(), bData->userData->payload.end(), array);
auto inStream = make_shared<BitwiseInputStream>(bData->userData->payload);
int dataLen = inStream->available() / 4; // 4-bit packed DTMF digit encoding.
int numFields = bData->userData->numFields;
if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
throw runtime_error("IS-91 voicemail status decoding failed");
}
auto addr = make_shared<CdmaSmsAddress>();
addr->digitMode = CdmaSmsAddress::DIGIT_MODE_4BIT_DTMF;
addr->origBytes = bData->userData->payload;
addr->numberOfDigits = (uint8_t) numFields;
decodeSmsAddress(addr);
bData->callbackNumber = addr;
}
void BearerData::decodeIs91ShortMessage(std::shared_ptr<BearerData> bData) {
//uint8_t array[bData->userData->payload.size()];
//std::copy(bData->userData->payload.begin(), bData->userData->payload.end(), array);
auto inStream = make_shared<BitwiseInputStream>(bData->userData->payload);
int dataLen = inStream->available() / 6; // 6-bit packed character encoding.
int numFields = bData->userData->numFields;
// dataLen may be > 14 characters due to octet padding
if ((numFields > 14) || (dataLen < numFields)) {
throw runtime_error("IS-91 short message decoding failed");
}
string strbuf;
for (int i = 0; i < numFields; i++) {
strbuf.push_back(UserData::ASCII_MAP[inStream->read(6)]);
}
bData->userData->payloadStr = strbuf;
}
void BearerData::decodeIs91(std::shared_ptr<BearerData> bData) {
switch (bData->userData->msgType) {
case UserData::IS91_MSG_TYPE_VOICEMAIL_STATUS:
decodeIs91VoicemailStatus(bData);
break;
case UserData::IS91_MSG_TYPE_CLI:
decodeIs91Cli(bData);
break;
case UserData::IS91_MSG_TYPE_SHORT_MESSAGE_FULL:
case UserData::IS91_MSG_TYPE_SHORT_MESSAGE:
decodeIs91ShortMessage(bData);
break;
default:
throw runtime_error(
string("unsupported IS-91 message type (")
+ std::to_string(bData->userData->msgType) + string(")"));
}
}
std::shared_ptr<BearerData> BearerData::decode(std::vector<uint8_t> smsData,
int serviceCategory) {
//uint8_t array[smsData.size()];
//std::copy(smsData.begin(), smsData.end(), array);
auto inStream = make_shared<BitwiseInputStream>(smsData);
shared_ptr<BearerData> bData = make_shared<BearerData>();
int foundSubparamMask = 0;
while (inStream->available() > 0) {
uint32_t subparamId = inStream->read((uint32_t) 8);
int subparamIdBit = 1 << subparamId;
// int is 4 bytes. This duplicate check has a limit to Id number up to 32 (4*8)
// as 32th bit is the max bit in int.
// Per 3GPP2 C.S0015-B Table 4.5-1 Bearer Data Subparameter Identifiers:
// last defined subparam ID is 23 (00010111 = 0x17 = 23).
// Only do duplicate subparam ID check if subparam is within defined value as
// reserved subparams are just skipped.
if ((foundSubparamMask & subparamIdBit) != 0
&& (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER
&& subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
throw runtime_error(
string("illegal duplicate subparameter (")
+ std::to_string(subparamId) + string(")"));
}
bool decodeSuccess;
switch (subparamId) {
case SUBPARAM_MESSAGE_IDENTIFIER:
decodeSuccess = decodeMessageId(bData, inStream);
break;
case SUBPARAM_USER_DATA:
decodeSuccess = decodeUserData(bData, inStream);
break;
case SUBPARAM_USER_RESPONSE_CODE:
decodeSuccess = decodeUserResponseCode(bData, inStream);
break;
case SUBPARAM_REPLY_OPTION:
decodeSuccess = decodeReplyOption(bData, inStream);
break;
case SUBPARAM_NUMBER_OF_MESSAGES:
decodeSuccess = decodeMsgCount(bData, inStream);
break;
case SUBPARAM_CALLBACK_NUMBER:
decodeSuccess = decodeCallbackNumber(bData, inStream);
break;
case SUBPARAM_MESSAGE_STATUS:
decodeSuccess = decodeMsgStatus(bData, inStream);
break;
case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream);
break;
case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
decodeSuccess = decodeValidityAbs(bData, inStream);
break;
case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
decodeSuccess = decodeValidityRel(bData, inStream);
break;
case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream);
break;
case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
decodeSuccess = decodeDeferredDeliveryRel(bData, inStream);
break;
case SUBPARAM_PRIVACY_INDICATOR:
decodeSuccess = decodePrivacyIndicator(bData, inStream);
break;
case SUBPARAM_LANGUAGE_INDICATOR:
decodeSuccess = decodeLanguageIndicator(bData, inStream);
break;
case SUBPARAM_MESSAGE_DISPLAY_MODE:
decodeSuccess = decodeDisplayMode(bData, inStream);
break;
case SUBPARAM_PRIORITY_INDICATOR:
decodeSuccess = decodePriorityIndicator(bData, inStream);
break;
case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
decodeSuccess = decodeMsgDeliveryAlert(bData, inStream);
break;
case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
decodeSuccess = decodeDepositIndex(bData, inStream);
break;
case SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA:
decodeSuccess = decodeServiceCategoryProgramData(bData, inStream);
break;
default:
decodeSuccess = decodeReserved(bData, inStream, subparamId);
}
if (decodeSuccess
&& (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER
&& subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
foundSubparamMask |= subparamIdBit;
}
}
if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
throw runtime_error("missing MESSAGE_IDENTIFIER subparam");
}
if (bData->userData != nullptr) {
if (isCmasAlertCategory(serviceCategory)) {
decodeCmasUserData(bData, serviceCategory);
} else if (bData->userData->msgEncoding
== UserData::ENCODING_IS91_EXTENDED_PROTOCOL) {
if ((foundSubparamMask ^ (1 << SUBPARAM_MESSAGE_IDENTIFIER)
^ (1 << SUBPARAM_USER_DATA)) != 0) {
// Rlog.e(LOG_TAG, "IS-91 must occur without extra subparams (" +
// foundSubparamMask + ")");
}
decodeIs91(bData);
} else {
decodeUserDataPayload(bData->userData, bData->hasUserDataHeader);
}
}
return bData;
}
std::string BearerData::toString() {
string builder;
builder.append("BearerData ");
builder.append("{ messageType=" + std::to_string(messageType));
builder.append(", messageId=" + std::to_string(messageId));
builder.append(
string(", priority=")
+ (priorityIndicatorSet ? std::to_string(priority) : "unset"));
builder.append(
string(", privacy=")
+ (privacyIndicatorSet ? std::to_string(privacy) : "unset"));
builder.append(
string(", alert=")
+ (alertIndicatorSet ? std::to_string(alert) : "unset"));
builder.append(
string(", displayMode=")
+ (displayModeSet ? std::to_string(displayMode) : "unset"));
builder.append(
string(", language=")
+ (languageIndicatorSet ? std::to_string(language) : "unset"));
builder.append(
string(", errorClass=")
+ (messageStatusSet ? std::to_string(errorClass) : "unset"));
builder.append(
string(", msgStatus=")
+ (messageStatusSet ? std::to_string(messageStatus) : "unset"));
builder.append(
string(
", msgCenterTimeStamp= unset") /*+ string (std::asctime(&msgCenterTimeStamp))*/);
builder.append(
string(
", validityPeriodAbsolute= unset")/* + string(std::asctime(&validityPeriodAbsolute)))*/);
builder.append(
string(", validityPeriodRelative= ")
+ ((validityPeriodRelativeSet) ?
std::to_string(validityPeriodRelative) : "unset"));
builder.append(
string(
", deferredDeliveryTimeAbsolute= ") /*+ string(std::asctime(&deferredDeliveryTimeAbsolute))*/);
builder.append(
string(", deferredDeliveryTimeRelative=")
+ ((deferredDeliveryTimeRelativeSet) ?
std::to_string(deferredDeliveryTimeRelative) : "unset"));
builder.append(", userAckReq=" + std::to_string(userAckReq));
builder.append(", deliveryAckReq=" + std::to_string(deliveryAckReq));
builder.append(", readAckReq=" + std::to_string(readAckReq));
builder.append(", reportReq=" + std::to_string(reportReq));
builder.append(", numberOfMessages=" + std::to_string(numberOfMessages));
builder.append(string(", callbackNumber=") + string(callbackNumber ? callbackNumber->toString() : "unset"));
builder.append(", depositIndex=" + std::to_string(depositIndex));
builder.append(", hasUserDataHeader=" + std::to_string(hasUserDataHeader));
builder.append(
", userData=" + string(userData ? userData->toString() : "unset"));
builder.append(" }");
return builder;
}