* Copyright (C) 2023 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_common_utils.h"
#include <ctime>
#include "securec.h"
#include "telephony_log_wrapper.h"
namespace OHOS {
namespace Telephony {
static constexpr uint8_t SMS_ENCODE_GSM_BIT = 7;
static constexpr uint8_t MAX_GSM_7BIT_DATA_LEN = 160;
static constexpr uint8_t SMS_BYTE_BIT = 8;
static constexpr uint16_t SEC_PER_HOUR = 3600;
static constexpr uint8_t BASE_GSM_YEAR = 100;
static constexpr uint8_t MAX_ABS_TIME_LEN = 32;
static constexpr uint8_t HEX_NUM_A = 0x0A;
static constexpr uint8_t HEX_NUM_B = 0x0B;
static constexpr uint8_t HEX_NUM_C = 0x0C;
static constexpr uint8_t MIN_PRINTABLE_CHAR = 32;
static constexpr uint8_t MAX_PRINTABLE_CHAR = 127;
uint16_t SmsCommonUtils::Pack7bitChar(
const uint8_t *userData, uint16_t dataLen, uint8_t fillBits, uint8_t *packData, uint16_t packLen)
{
uint16_t dstIdx = 0;
if (userData == nullptr || packData == nullptr || dataLen > MAX_GSM_7BIT_DATA_LEN) {
TELEPHONY_LOGE("userData error.");
return dstIdx;
}
auto shift = fillBits;
if (shift > 0) {
dstIdx = 1;
}
uint16_t srcIdx = 0;
while (srcIdx < dataLen && dstIdx < packLen) {
if (shift == 0) {
packData[dstIdx] = userData[srcIdx];
shift = SMS_ENCODE_GSM_BIT;
srcIdx++;
dstIdx++;
if (srcIdx >= dataLen) {
break;
}
}
if (shift > 1) {
packData[dstIdx - 1] |= userData[srcIdx] << shift;
packData[dstIdx] = userData[srcIdx] >> (SMS_BYTE_BIT - shift);
srcIdx++;
dstIdx++;
shift--;
} else if (shift == 1) {
packData[dstIdx - 1] |= userData[srcIdx] << shift;
shift--;
srcIdx++;
}
}
return dstIdx;
}
uint16_t SmsCommonUtils::Unpack7bitChar(
const uint8_t *tpdu, uint16_t dataLen, uint8_t fillBits, uint8_t *unpackData, uint16_t unpackDataLen)
{
uint16_t srcIdx = 0;
uint16_t dstIdx = 0;
auto shift = fillBits;
if (unpackData == nullptr || tpdu == nullptr || dataLen == 0 || unpackDataLen == 0 || dataLen > unpackDataLen) {
TELEPHONY_LOGE("userData error.");
return dstIdx;
}
if (shift > 0) {
srcIdx = 1;
}
for (; srcIdx < dataLen && dstIdx < unpackDataLen; dstIdx++) {
if (shift == 0) {
unpackData[dstIdx] = tpdu[srcIdx] & 0x7F;
shift = SMS_ENCODE_GSM_BIT;
srcIdx++;
dstIdx++;
if (dstIdx >= dataLen) {
dstIdx--;
break;
}
}
if (shift > 0 && srcIdx < dataLen && dstIdx < unpackDataLen) {
unpackData[dstIdx] =
(static_cast<unsigned int>(tpdu[srcIdx - 1]) >> shift) + (tpdu[srcIdx] << (SMS_BYTE_BIT - shift));
unpackData[dstIdx] &= 0x7F;
shift--;
if (shift > 0) {
srcIdx++;
}
}
}
return dstIdx;
}
uint16_t SmsCommonUtils::Unpack7bitCharForCBPdu(
const uint8_t *tpdu, uint16_t dataLen, uint8_t fillBits, uint8_t *unpackData, uint16_t unpackDataLen)
{
uint16_t srcIdx = 0;
uint16_t dstIdx = 0;
auto shift = fillBits;
if (unpackData == nullptr || tpdu == nullptr || dataLen == 0 || unpackDataLen == 0 || dataLen > unpackDataLen) {
TELEPHONY_LOGE("userData error.");
return dstIdx;
}
if (shift > 0) {
srcIdx = 1;
}
for (; srcIdx < dataLen && dstIdx < unpackDataLen;) {
if (shift == 0) {
unpackData[dstIdx] = tpdu[srcIdx] & 0x7F;
shift = SMS_ENCODE_GSM_BIT;
srcIdx++;
dstIdx++;
}
if (shift > 0 && srcIdx < dataLen && dstIdx < unpackDataLen) {
unpackData[dstIdx] =
(static_cast<unsigned int>(tpdu[srcIdx - 1]) >> shift) + (tpdu[srcIdx] << (SMS_BYTE_BIT - shift));
unpackData[dstIdx] &= 0x7F;
shift--;
if (shift > 0) {
srcIdx++;
}
dstIdx++;
}
}
if (dstIdx >= unpackDataLen) {
TELEPHONY_LOGE("dstIdx:%{public}d", dstIdx);
return 0;
}
uint8_t value = 0;
if (shift == 0) {
value = tpdu[srcIdx] >> shift;
} else if (srcIdx > 1) {
value = tpdu[srcIdx - 1] >> shift;
}
if (value >= MIN_PRINTABLE_CHAR && value <= MAX_PRINTABLE_CHAR) {
unpackData[dstIdx] = value;
dstIdx++;
}
TELEPHONY_LOGI("dstIdx:%{public}d", dstIdx);
return dstIdx;
}
uint8_t SmsCommonUtils::DigitToDtmfChar(const uint8_t c)
{
if (c == '0') {
return HEX_NUM_A;
} else if (c == '*') {
return HEX_NUM_B;
} else if (c == '#') {
return HEX_NUM_C;
} else {
return (c - '0');
}
}
uint8_t SmsCommonUtils::DtmfCharToDigit(const uint8_t c)
{
switch (c) {
case HEX_NUM_B:
return '*';
case HEX_NUM_C:
return '#';
case HEX_NUM_A:
return '0';
default:
return (c + '0');
}
}
int64_t SmsCommonUtils::ConvertTime(const struct SmsTimeAbs &timeAbs)
{
time_t rawtime;
struct tm tmObj;
if (memset_s(&tmObj, sizeof(struct tm), 0x00, sizeof(tm)) != EOK) {
return time(nullptr);
}
tmObj.tm_year = (timeAbs.year + BASE_GSM_YEAR);
tmObj.tm_mon = (timeAbs.month - 0x01);
tmObj.tm_mday = timeAbs.day;
tmObj.tm_hour = timeAbs.hour;
tmObj.tm_min = timeAbs.minute;
tmObj.tm_sec = timeAbs.second;
tmObj.tm_isdst = 0;
rawtime = mktime(&tmObj);
GetDisplayTime(rawtime);
rawtime -= (timeAbs.timeZone * (SEC_PER_HOUR / 0x04));
GetDisplayTime(rawtime);
rawtime -= timezone;
GetDisplayTime(rawtime);
return rawtime;
}
void SmsCommonUtils::GetDisplayTime(const time_t &rawtime)
{
struct tm tmObj;
char displayTime[MAX_ABS_TIME_LEN];
if (memset_s(&tmObj, sizeof(struct tm), 0x00, sizeof(tm)) != EOK) {
TELEPHONY_LOGE("GetDisplayTime memset fail.");
return;
}
if (memset_s(displayTime, sizeof(displayTime), 0x00, sizeof(displayTime)) != EOK) {
TELEPHONY_LOGE("GetDisplayTime memset fail.");
return;
}
localtime_r(&rawtime, &tmObj);
if (strftime(displayTime, MAX_ABS_TIME_LEN, "%Y-%02m-%02d %T %z", &tmObj) <= 0) {
TELEPHONY_LOGE("strftime error.");
return;
}
}
}
}