* Copyright (C) 2021 Huawei Device Co., Ltd.
* 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 "sms_wap_push_buffer.h"
#include "securec.h"
#include "sms_constants_utils.h"
#include "string_utils.h"
#include "telephony_log_wrapper.h"
namespace OHOS {
namespace Telephony {
SmsWapPushBuffer::SmsWapPushBuffer() {}
SmsWapPushBuffer::~SmsWapPushBuffer()
{
if (pduBuffer_ != nullptr) {
pduBuffer_.reset();
}
}
std::unique_ptr<char[]> SmsWapPushBuffer::ReadDataBuffer(uint32_t desLen)
{
return ReadDataBuffer(curPosition_, desLen);
}
std::unique_ptr<char[]> SmsWapPushBuffer::ReadDataBuffer(uint32_t offset, uint32_t desLen)
{
if ((desLen > totolLength_) || ((static_cast<uint64_t>(offset) + desLen) > totolLength_)) {
return nullptr;
}
if (desLen > MMS_PDU_MAX_SIZE) {
TELEPHONY_LOGE("desLen over size error");
return nullptr;
}
std::unique_ptr<char[]> result = std::make_unique<char[]>(desLen);
if (result == nullptr) {
return nullptr;
}
if (memcpy_s(result.get(), desLen, &pduBuffer_[offset], desLen) != EOK) {
return nullptr;
}
return result;
}
bool SmsWapPushBuffer::WriteRawStringBuffer(const std::string &inSrc)
{
uint32_t len = inSrc.length();
if (len > MMS_PDU_MAX_SIZE) {
TELEPHONY_LOGE("create wappush input source string over length error.");
return false;
}
if (pduBuffer_) {
pduBuffer_.reset();
}
pduBuffer_ = std::make_unique<char[]>(len);
if (!pduBuffer_) {
TELEPHONY_LOGE("wap push make unique fail.");
return false;
}
if (memcpy_s(pduBuffer_.get(), len, inSrc.data(), len) != EOK) {
TELEPHONY_LOGE("wap push memcpy_s fail.");
return false;
}
totolLength_ = len;
return true;
}
bool SmsWapPushBuffer::WriteDataBuffer(std::unique_ptr<char[]> inBuff, uint32_t len)
{
if (inBuff == nullptr) {
TELEPHONY_LOGE("wap push inBuff is null.");
return false;
}
if (len <= 0 || len > MMS_PDU_MAX_SIZE) {
TELEPHONY_LOGE("wap push len invalid .");
return false;
}
if (pduBuffer_) {
pduBuffer_.reset();
}
pduBuffer_ = std::make_unique<char[]>(len);
if (!pduBuffer_) {
TELEPHONY_LOGE("wap push make unique fail.");
return false;
}
if (memcpy_s(pduBuffer_.get(), len, inBuff.get(), len) != EOK) {
TELEPHONY_LOGE("wap push memcpy_s fail.");
return false;
}
totolLength_ = len;
return true;
}
uint32_t SmsWapPushBuffer::GetCurPosition() const
{
return curPosition_;
}
uint32_t SmsWapPushBuffer::GetSize() const
{
return totolLength_;
}
bool SmsWapPushBuffer::PeekOneByte(uint8_t &oneByte)
{
if (curPosition_ >= totolLength_) {
TELEPHONY_LOGE("wap push current position invalid.");
return false;
}
oneByte = pduBuffer_[curPosition_];
return true;
}
bool SmsWapPushBuffer::GetOneByte(uint8_t &oneByte)
{
if (curPosition_ >= totolLength_) {
TELEPHONY_LOGE("wap push current position invalid.");
return false;
}
oneByte = pduBuffer_[curPosition_];
curPosition_++;
return true;
}
bool SmsWapPushBuffer::IncreasePointer(uint32_t offset)
{
if ((offset > totolLength_) || ((curPosition_ + offset) > totolLength_)) {
TELEPHONY_LOGE("wap push current position invalid.");
return false;
}
curPosition_ += offset;
return true;
}
bool SmsWapPushBuffer::DecreasePointer(uint32_t offset)
{
if (offset > curPosition_) {
TELEPHONY_LOGE("wap push current position invalid.");
return false;
}
curPosition_ -= offset;
return true;
}
* @brief DecodeUintvar
* wap-230-wsp-20010705-a section:8.4.2.1 Basic rules
* Uintvar-integer = 1*5 OCTET
* @param uintVar
* @param count
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeUintvar(uint32_t &uintVar, uint32_t &count)
{
const uint8_t setNotHighestBitZero = 0x80;
const uint8_t setHighestBitZero = 0x7f;
count = 0;
uint8_t oneByte = 0;
if (!GetOneByte(oneByte)) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
count++;
uintVar = 0;
while ((oneByte & setNotHighestBitZero) != 0) {
uintVar = uintVar << 0x07;
uintVar |= oneByte & setHighestBitZero;
if (!GetOneByte(oneByte)) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
count++;
}
uintVar = uintVar << 0x07;
uintVar |= oneByte & setHighestBitZero;
return true;
}
* @brief DecodeShortLength
* wap-230-wsp-20010705-a.pdf section:8.4.2.2 Length
* Short-length = <Any octet 0-30>
* @param sValueLength
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeShortLength(uint8_t &sValueLength)
{
const unsigned char minShortOctet = 30;
uint8_t oneByte = 0;
if (!GetOneByte(oneByte)) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
if (oneByte <= minShortOctet) {
sValueLength = oneByte;
return true;
}
return false;
}
* @brief DecodeValueLengthReturnLen
* value-length = short-length | (Length-quote Length)
* short-length = 0~30
* Length-quote = 31
* (Length-quote Length) = Length-quote + Uintvar-length
* @param valueLength
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeValueLengthReturnLen(uint32_t &valueLength, uint32_t &length)
{
const uint8_t lengthQuote = 0x1f;
const uint8_t maxShortLength = 30;
length = 0;
valueLength = 0;
uint32_t uintvar = 0;
uint8_t oneByte = 0;
if (!GetOneByte(oneByte)) {
DecreasePointer(1);
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
if (oneByte <= maxShortLength) {
valueLength = oneByte;
length = 1;
return true;
} else if (oneByte == lengthQuote) {
uint32_t count = 0;
if (!DecodeUintvar(uintvar, count)) {
TELEPHONY_LOGE("wap push DecodeUintvar fail.");
return false;
}
valueLength = uintvar;
length = count + 1;
return true;
}
return false;
}
* @brief DecodeValueLength
* value-length = short-length | (Length-quote Length)
* short-length = 0~30
* Length-quote = 31
* (Length-quote Length) = Length-quote + Uintvar-length
* @param valueLength
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeValueLength(uint32_t &valueLength)
{
const uint8_t lengthQuote = 0x1f;
const uint8_t maxShortLength = 30;
valueLength = 0;
uint32_t uintvar = 0;
uint8_t oneByte = 0;
if (!GetOneByte(oneByte)) {
DecreasePointer(1);
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
if (oneByte <= maxShortLength) {
valueLength = oneByte;
return true;
} else if (oneByte == lengthQuote) {
uint32_t count = 0;
if (!DecodeUintvar(uintvar, count)) {
TELEPHONY_LOGE("wap push DecodeUintvar fail.");
return false;
}
valueLength = uintvar;
return true;
}
return false;
}
* @brief CharIsToken
* RFC2616 section:2.2 Basic Rules
* CHAR = <any US-ASCII character (octets 0 - 127)>
* CTL = <any US-ASCII control character
* (octets 0 - 31) and DEL (127)>
* separators = "(" | ")" | "<" | ">" | "@"
* | "," | ";" | ":" | "\" | <">
* | "/" | "[" | "]" | "?" | "="
* | "{" | "}" | SP | HT
* @param oneByte
* @return true
* @return false
*/
bool SmsWapPushBuffer::CharIsToken(uint8_t oneByte)
{
const uint8_t minToken = 33;
const uint8_t maxToken = 126;
if (oneByte < minToken || oneByte > maxToken) {
return false;
}
std::set<uint8_t> token = { '"', '(', ')', '/', ',', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' };
return !token.count(oneByte);
}
* @brief DecodeTokenText
* wap-230-wsp-20010705-a section:8.4.2.2 Length
* Token-text = Token End-of-string
* End-of-string = <Octet 0>
* @param str
* @param len
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeTokenText(std::string &str, uint32_t &len)
{
const uint8_t minToken = 33;
const uint8_t maxToken = 126;
len = 0;
str.clear();
uint8_t oneByte = 0;
if (!PeekOneByte(oneByte)) {
TELEPHONY_LOGE("wap push PeekOneByte fail.");
return false;
}
if (oneByte < minToken || oneByte > maxToken) {
TELEPHONY_LOGE("wap push DecodeTokenText fail.");
return false;
}
while (GetOneByte(oneByte)) {
if (oneByte != 0) {
if (CharIsToken(oneByte)) {
str += oneByte;
len++;
}
} else {
break;
}
}
return (len > 0) ? true : false;
}
* @brief DecodeText
* wap-230-wsp-20010705-a section:8.4.2.1 Basic rules
* Text-string = [Quote] *TEXT End-of-string
* Quote = <Octet 127>
* End-of-string = <Octet 0>
* @param str
* @param len
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeText(std::string &str, uint32_t &len)
{
const unsigned char quoteChar = 127;
len = 0;
str.clear();
uint8_t oneByte = 0;
if (!GetOneByte(oneByte)) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
if (oneByte != quoteChar) {
this->DecreasePointer(1);
} else {
len++;
}
while (GetOneByte(oneByte)) {
if (oneByte != 0) {
str += oneByte;
len++;
} else {
break;
}
}
return (len > 0) ? true : false;
}
* @brief DecodeQuotedText
* wap-230-wsp-20010705-a section:8.4.2.1 Basic rules
* Quoted-string = <Octet 34> *TEXT End-of-string
* The TEXT encodes an RFC2616 Quoted-string with the enclosing quotation-marks <"> removed
* @param str
* @param len
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeQuotedText(std::string &str, uint32_t &len)
{
const uint8_t quotedFlag = 0x22;
uint8_t oneByte = 0;
len = 0;
str.clear();
while (GetOneByte(oneByte)) {
if (oneByte != 0) {
if (oneByte != quotedFlag) {
str += oneByte;
}
len++;
} else {
break;
}
}
return (len > 0) ? true : false;
}
* @brief DecodeShortInteger
* wap-230-wsp-20010705-a section:8.4.2.1 Basic rules
* Short-integer = OCTET
* Integers in range 0-127 shall be encoded as a one octet value with
* the most significant bit set to one (1xxx xxxx) and with the value
* in the remaining least significant bits
* @param sInteger
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeShortInteger(uint8_t &sInteger)
{
const uint8_t setHighestBitZero = 0x7f;
const uint8_t maxShortInteger = 0x7f;
sInteger = 0;
uint8_t oneByte = 0;
if (!GetOneByte(oneByte)) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
if (oneByte > maxShortInteger) {
sInteger = oneByte & setHighestBitZero;
return true;
}
return false;
}
* @brief DecodeLongInteger
* Long-integer = [Short-length] [Multi-octet-integer]
* Short-length = 1 byte
* Multi-octet-integer = <Short-length> bytes
* @param value
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeLongInteger(uint64_t &value)
{
unsigned char oneByte = 0;
uint64_t result = 0;
uint32_t valuelength = 0;
if (GetOneByte(oneByte) != true) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
if (oneByte > LONG_VALUE_LEN_MAX) {
return false;
}
valuelength = oneByte;
for (uint32_t i = 0; i < valuelength; i++) {
if (GetOneByte(oneByte) != true) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
result = (result << 0x08);
result |= oneByte;
}
value = result;
return true;
}
* @brief DecodeInteger
* Integer-Value = Short-integer | Long-integer
* @param iInteger
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeInteger(uint64_t &iInteger)
{
iInteger = 0;
if (DecodeIsShortInt()) {
uint8_t sInteger = 0;
if (DecodeShortInteger(sInteger)) {
iInteger = sInteger;
return true;
}
} else {
if (DecodeLongInteger(iInteger)) {
return true;
}
}
return false;
}
* @brief DecodeIsShortInt
* (128 - 255) It is an encoded 7-bit value; this header has no more data
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeIsShortInt()
{
uint8_t oneByte = 0;
PeekOneByte(oneByte);
if (oneByte > 0x7F) {
return true;
}
return false;
}
* @brief DecodeIsString
* (32 - 127) The value is a text string, terminated by a zero octet (NUL character)
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeIsString()
{
uint8_t oneByte = 0;
PeekOneByte(oneByte);
if (0x20 <= oneByte && 0x7f >= oneByte) {
return true;
}
return false;
}
* @brief DecodeIsValueLength
* (0 - 30) This octet is followed by the indicated number (0 –30) of data octets
* 31 This octet is followed by a uintvar, which indicates the number of data octets after it
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeIsValueLength()
{
uint8_t oneByte = 0;
PeekOneByte(oneByte);
if (oneByte <= 0x1f) {
return true;
}
return false;
}
* @brief DecodeExtensionMedia
*
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeExtensionMedia()
{
return false;
}
* @brief DecodeConstrainedEncoding
*
* @return true
* @return false
*/
bool SmsWapPushBuffer::DecodeConstrainedEncoding()
{
return false;
}
bool SmsWapPushBuffer::DecodeTextValue(std::string &str, bool &isNoValue)
{
const uint8_t minTextToken = 31;
str.clear();
unsigned char oneByte = 0;
if (GetOneByte(oneByte) != true) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
if ((oneByte & 0x80) == 0x00 && oneByte > minTextToken) {
std::string field = "";
uint32_t fieldLength = 0;
if (!DecodeTokenText(field, fieldLength)) {
TELEPHONY_LOGE("wap push DecodeTokenText fail.");
return false;
}
} else {
uint64_t fieldId = 0;
if (!DecodeInteger(fieldId)) {
TELEPHONY_LOGE("wap push DecodeInteger fail.");
return false;
}
}
bool bNoValue = false;
if (!DecodeNoValue(bNoValue)) {
TELEPHONY_LOGE("wap push DecodeNoValue fail.");
return false;
}
if (bNoValue) {
isNoValue = true;
return true;
} else {
if (DecreasePointer(1) != true) {
TELEPHONY_LOGE("wap push DecreasePointer fail.");
return false;
}
}
uint64_t fieldValue = 0;
if (DecodeInteger(fieldValue)) {
str = std::to_string(fieldValue);
return true;
}
uint32_t valueLength = 0;
if (DecodeTokenText(str, valueLength)) {
if (str.length() > 1 && str.at(0) == '\"') {
str = str.substr(1, str.length() - 1);
}
return true;
}
return false;
}
bool SmsWapPushBuffer::DecodeNoValue(bool &isNoValue)
{
unsigned char oneByte = 0;
if (GetOneByte(oneByte) != true) {
TELEPHONY_LOGE("wap push GetOneByte fail.");
return false;
}
isNoValue = (oneByte == 0) ? true : false;
return true;
}
void SmsWapPushBuffer::MarkPosition()
{
savePosition_ = curPosition_;
}
void SmsWapPushBuffer::UnMarkPosition()
{
curPosition_ = savePosition_;
}
}
}