1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "sim_number_decode.h"
17 #include <set>
18 #include <sstream>
19 #include <iomanip>
20 
21 using namespace std;
22 
23 namespace OHOS {
24 namespace Telephony {
HexToStr(const std::vector<uint8_t> & arr)25 static std::string HexToStr(const std::vector<uint8_t> &arr)
26 {
27     std::stringstream ss;
28     for (const auto &v : arr) {
29         ss << std::hex << std::uppercase << std::setw(NEW_WIDTH) << std::setfill('0') << v;
30     }
31     return ss.str();
32 }
33 
IsNumber(const char num)34 inline static bool IsNumber(const char num)
35 {
36     return (num >= '0' && num <= '9');
37 }
38 
IsPlusNumber(const char num)39 inline static bool IsPlusNumber(const char num)
40 {
41     return IsNumber(num) || (num == '+');
42 }
43 
IsSharpStar(const char num)44 inline static bool IsSharpStar(const char num)
45 {
46     return num == '#' || num == '*';
47 }
48 
IsValidNumberChar(const char num)49 inline static bool IsValidNumberChar(const char num)
50 {
51     return IsPlusNumber(num) || IsSharpStar(num);
52 }
53 
IsValidNumberString(const std::string & number)54 bool SimNumberDecode::IsValidNumberString(const std::string &number)
55 {
56     for (const auto &num : number) {
57         if (!IsValidNumberChar(num)) {
58             return false;
59         }
60     }
61     return true;
62 }
63 
chooseExtendedByType(const int bcdExtType)64 const std::string *SimNumberDecode::chooseExtendedByType(const int bcdExtType)
65 {
66     if (bcdExtType == BCD_TYPE_ADN) {
67         return &BCD_ADN_EXTENTION;
68     } else if (bcdExtType == BCD_TYPE_CALLER) {
69         return &BCD_CALLER_EXTENTION;
70     }
71     return nullptr;
72 }
73 
CharToBCD(const char c,uint8_t & result,const int bcdExtType)74 bool SimNumberDecode::CharToBCD(const char c, uint8_t &result, const int bcdExtType)
75 {
76     if (c >= '0' && c <= '9') {
77         result = c - '0';
78         return true;
79     }
80     const std::string *extendedPtr = chooseExtendedByType(bcdExtType);
81     if (!extendedPtr) {
82         TELEPHONY_LOGE("Unknow bcdExtType:[%{public}d]", bcdExtType);
83         return false;
84     }
85     const std::string &extended = *extendedPtr;
86     const size_t chrIdx = extended.find(c);
87     if (chrIdx == std::string::npos) {
88         TELEPHONY_LOGE("invalid char for BCD %{public}d", c);
89         return false;
90     }
91     result = static_cast<uint8_t>(chrIdx + CHAR_START);
92     return true;
93 }
94 
BcdToChar(const uint8_t bcdCode,char & result,const int bcdExtType)95 bool SimNumberDecode::BcdToChar(const uint8_t bcdCode, char &result, const int bcdExtType)
96 {
97     const int32_t surplus = static_cast<int32_t>(bcdCode) - CHAR_START;
98     if (surplus < INIT_VAL) {
99         result = '0' + bcdCode;
100         return true;
101     }
102     const std::string *extendedPtr = chooseExtendedByType(bcdExtType);
103     if (!extendedPtr) {
104         TELEPHONY_LOGE("Unknow bcdExtType:[%{public}d]", bcdExtType);
105         return false;
106     }
107     if (static_cast<size_t>(surplus) >= extendedPtr->size()) {
108         TELEPHONY_LOGE("Unknow bcdCode:[%{public}d]", bcdCode);
109         return false;
110     }
111     result = extendedPtr->at(surplus);
112     return true;
113 }
114 
NumberConvertToBCD(const std::string & number,std::vector<uint8_t> & bcdCodes,const bool includeLen,const int bcdExtType)115 bool SimNumberDecode::NumberConvertToBCD(
116     const std::string &number, std::vector<uint8_t> &bcdCodes, const bool includeLen, const int bcdExtType)
117 {
118     TELEPHONY_LOGI(
119         "SimNumberDecode::NumberConvertToBCD begin_B with "
120         "number,isCludeLen:%{public}d,bcdExtType:%{public}d",
121         includeLen, bcdExtType);
122     const bool hasPlus = (number.find('+') != std::string::npos);
123     uint8_t length = number.length();
124     if (hasPlus) {
125         --length;
126     }
127     if (includeLen) {
128         bcdCodes.push_back(length);
129     }
130     bcdCodes.push_back(hasPlus ? FLAG_INTERNATIONAL : FLAG_UNKNOWN);
131 
132     size_t count = INIT_VAL;
133     for (const auto &num : number) {
134         if (num == '+') {
135             continue;
136         }
137         uint8_t code = INIT_VAL;
138         if (!CharToBCD(num, code, bcdExtType)) {
139             TELEPHONY_LOGI("occur error in CharToBCD(num:'%{public}d',bcdExtType:'%{public}d')", num, bcdExtType);
140             return false;
141         }
142         if (count % EVEN == 1) {
143             bcdCodes.back() |= (code << FOUR_BIT);
144         } else {
145             bcdCodes.push_back(code);
146         }
147         ++count;
148     }
149     if (count % EVEN == 1) {
150         bcdCodes.back() |= HI_FOUR;
151     }
152     return true;
153 }
154 
BCDConvertToString(const std::shared_ptr<unsigned char> bytesData,int offset,int length,int bcdExtType)155 std::string SimNumberDecode::BCDConvertToString(
156     const std::shared_ptr<unsigned char> bytesData, int offset, int length, int bcdExtType)
157 {
158     uint8_t *arr = bytesData.get();
159     if (!arr) {
160         TELEPHONY_LOGE("BCDConvertToString fail because bytesData is nullptr!!");
161         return "";
162     }
163     std::vector<uint8_t> bcdCode;
164     for (int i = INIT_VAL; i < length; ++i) {
165         bcdCode.push_back(arr[offset + i]);
166     }
167     std::string res;
168     if (!BCDConvertToString(bcdCode.begin(), bcdCode.end(), res, bcdExtType)) {
169         TELEPHONY_LOGE("occur error in BCDConvertToString for '%{public}s by bcdExtType:%{public}d",
170             HexToStr(bcdCode).c_str(), bcdExtType);
171     }
172     return res;
173 }
174 
BCDSectionConvertToString(const std::vector<uint8_t>::const_iterator & codeBeg,const std::vector<uint8_t>::const_iterator & codeEnd,std::string & number,const int bcdExtType)175 bool SimNumberDecode::BCDSectionConvertToString(const std::vector<uint8_t>::const_iterator &codeBeg,
176     const std::vector<uint8_t>::const_iterator &codeEnd, std::string &number, const int bcdExtType)
177 {
178     for (std::vector<uint8_t>::const_iterator it = codeBeg; it != codeEnd; ++it) {
179         uint8_t loFourBit = (*it & LO_FOUR);
180         char c = INIT_VAL;
181         if (!BcdToChar(loFourBit, c, bcdExtType)) {
182             TELEPHONY_LOGE(
183                 "occur error in BcdToChar(bcd:'%{public}d',bcdExtType:'%{public}d')", loFourBit, bcdExtType);
184             return false;
185         }
186         number.push_back(c);
187         uint8_t hiFourBit = (*it >> SHIFT_FLAG) & HALF_BYTE;
188         if (hiFourBit == HALF_BYTE && (it + INC_ONE) == codeEnd) {
189             break;
190         }
191         if (!BcdToChar(hiFourBit, c, bcdExtType)) {
192             TELEPHONY_LOGE(
193                 "occur error in BcdToChar(bcd:'%{public}d',bcdExtType:'%{public}d')", loFourBit, bcdExtType);
194             return false;
195         }
196         number.push_back(c);
197     }
198     return true;
199 }
200 
BCDConvertToString(const std::vector<uint8_t>::const_iterator & codeBeg,const std::vector<uint8_t>::const_iterator & codeEnd,std::string & number,const int bcdExtType)201 bool SimNumberDecode::BCDConvertToString(const std::vector<uint8_t>::const_iterator &codeBeg,
202     const std::vector<uint8_t>::const_iterator &codeEnd, std::string &number, const int bcdExtType)
203 {
204     if (codeBeg == codeEnd) {
205         TELEPHONY_LOGE("occur error by iterator");
206         return false;
207     }
208     std::vector<uint8_t>::const_iterator it = codeBeg;
209     const bool prependPlus = (*it == FLAG_INTERNATIONAL);
210     ++it;
211     if (!BCDSectionConvertToString(it, codeEnd, number, bcdExtType)) {
212         TELEPHONY_LOGE(
213             "occur error to BCDSectionConvertToString by codes:'%{public}s' and bcdExtType:'%{public}d'",
214             HexToStr(std::vector<uint8_t>(it, codeEnd)).c_str(), bcdExtType);
215     }
216     if (!prependPlus) {
217         return true;
218     }
219     if (number.empty() || !IsValidNumberString(number)) {
220         TELEPHONY_LOGE("occur error at number after parse!! number");
221         return false;
222     }
223 
224     std::string::const_iterator numIt = number.begin();
225     /* not start with [#*] just prepend '+' */
226     if (!IsSharpStar(number.front())) {
227         number.insert(number.begin(), '+');
228         return true;
229     }
230     ++numIt;
231     /* started with two [#*] ends with # ,just append a +  */
232     if (IsSharpStar(*numIt) && (number.back() == '#')) {
233         number.push_back('+');
234         return true;
235     }
236     while ((numIt != number.end()) && IsPlusNumber(*numIt)) {
237         ++numIt;
238     }
239     /*  start with [#*] ;assume the data after last;insert head of data a + */
240     if ((numIt != number.end()) && (numIt + INC_ONE != number.end()) && IsSharpStar(*numIt)) {
241         number.insert(numIt + INC_ONE, '+');
242     }
243     return true;
244 }
245 } // namespace Telephony
246 } // namespace OHOS
247