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 "i18n_memory_adapter.h"
17 #include "securec.h"
18 #include "str_util.h"
19 #include "number_data.h"
20 
21 using namespace OHOS::I18N;
22 
StyleData(const StyleData & data)23 StyleData::StyleData(const StyleData &data)
24 {
25     decLen = data.decLen;
26     intLen = data.intLen;
27     percentIntLen = data.percentIntLen;
28     isTwoGroup = data.isTwoGroup;
29     if (data.numFormat != nullptr) {
30         int len = strlen(data.numFormat);
31         numFormat = NewArrayAndCopy(data.numFormat, len);
32     }
33     if (data.entireFormat != nullptr) {
34         int len = strlen(data.entireFormat);
35         entireFormat = I18nNewCharString(data.entireFormat, len);
36     }
37 }
38 
~StyleData()39 StyleData::~StyleData()
40 {
41     I18nFree(static_cast<void *>(numFormat));
42     I18nFree(static_cast<void *>(entireFormat));
43 }
44 
operator =(const StyleData & data)45 StyleData &StyleData::operator=(const StyleData &data)
46 {
47     decLen = data.decLen;
48     intLen = data.intLen;
49     percentIntLen = data.percentIntLen;
50     isTwoGroup = data.isTwoGroup;
51     if (data.numFormat != nullptr) {
52         int len = strlen(data.numFormat);
53         numFormat = I18nNewCharString(data.numFormat, len);
54     }
55     if (data.entireFormat != nullptr) {
56         int len = strlen(data.entireFormat);
57         entireFormat = I18nNewCharString(data.entireFormat, len);
58     }
59     return *this;
60 }
61 
SetNumSystem(std::string * numSym,const int numSize)62 void NumberData::SetNumSystem(std::string *numSym, const int numSize)
63 {
64     if (numSym == nullptr || numSize <= 0) {
65         return;
66     }
67     ArrayCopy(nativeNums, NUM_SIZE, numSym, numSize);
68     if (!(numSym[0]).empty() && ((numSym[0]).at(0) != '0')) {
69         isNative = true;
70     }
71 }
72 
Init(const char * pat,int patLen,const char * percentPat,int perPatLen)73 void NumberData::Init(const char *pat, int patLen, const char *percentPat, int perPatLen)
74 {
75     numberFormatPattern = I18nNewCharString(pat, patLen);
76     percentFormatPattern = I18nNewCharString(percentPat, perPatLen);
77     ParsePattern(pat, patLen);
78     ParsePercentPattern(percentPat, perPatLen);
79 }
80 
InitSign(const std::string * signs,int size)81 void NumberData::InitSign(const std::string *signs, int size)
82 {
83     if (signs == nullptr || size < PERCENT_SIGN_INDEX) {
84         return;
85     }
86     std::string decSign = signs[0]; // use array to store num data, first is decimal sign
87     std::string groupSign = signs[1]; // use array to store num data, second is group sign
88     std::string perSign = signs[PERCENT_SIGN_INDEX]; // use array to store num data, third is percent sign
89     const char *td = decSign.c_str();
90     decimal = I18nNewCharString(td, strlen(td));
91     const char *tdg = groupSign.c_str();
92     group = I18nNewCharString(tdg, strlen(tdg));
93     const char *tdp = perSign.c_str();
94     percent = I18nNewCharString(tdp, strlen(tdp));
95 }
96 
ParsePattern(const char * pattern,const int len)97 void NumberData::ParsePattern(const char *pattern, const int len)
98 {
99     bool isDec = CalculateDecLength(pattern, len);
100     CalculateIntLength(len - style.decLen, pattern, len, isDec);
101     if ((pattern != nullptr) && (strcmp(pattern, "#,##,##0.###")) == 0) {
102         style.isTwoGroup = true;
103     }
104     UpdateNumberFormat();
105 }
106 
CalculateDecLength(const char * pattern,const int len)107 bool NumberData::CalculateDecLength(const char *pattern, const int len)
108 {
109     if (pattern == nullptr || len <= 0) {
110         return false;
111     }
112     bool isDec = false;
113     int decLen = 0;
114     for (int i = 0; i < len; i++) { // calculate the format after decimal sign
115         char temp = pattern[i];
116         if (temp == '.') {
117             isDec = true;
118             continue;
119         }
120         if (isDec && ((temp == '#') || (temp == '0'))) {
121             decLen++;
122         }
123     }
124     style.decLen = decLen;
125     return isDec;
126 }
127 
CalculateIntLength(int intEndPos,const char * pattern,const int len,bool isDec)128 void NumberData::CalculateIntLength(int intEndPos, const char *pattern, const int len, bool isDec)
129 {
130     if (pattern == nullptr || len <= 0) {
131         return;
132     }
133     if (isDec) {
134         --intEndPos;
135     }
136     int intLen = 0;
137     for (; intEndPos > 0; --intEndPos) {
138         if (pattern[intEndPos - 1] != '0') {
139             break;
140         }
141         ++intLen;
142     }
143     style.intLen = intLen;
144 }
145 
ParsePercentPattern(const char * pattern,const int len)146 void NumberData::ParsePercentPattern(const char *pattern, const int len)
147 {
148     if (pattern == nullptr || len <= 0) {
149         return;
150     }
151     int perSignPos = 0; // 0 : no percent 1:left 2:right;
152     int space = 0; // 0 = 0020, 1 = c2a0
153     int hasSpace = 0;
154     if (pattern[0] == '%') {
155         perSignPos = LEFT;
156         if ((len >= 2) && pattern[1] == ' ') { // length >= 2 guarantees that we can safely get second byte
157             hasSpace = 1;
158         } else if (IsNoBreakSpace(pattern, len, true)) {
159             hasSpace = 1;
160             space = 1;
161         }
162     } else if (pattern[len - 1] == '%') {
163         perSignPos = RIGHT;
164         if ((len >= 2) && (pattern[len - 2] == ' ')) { // len - 2 position has a spacce
165             hasSpace = 1;
166         } else if (IsNoBreakSpace(pattern, len, false)) {
167             hasSpace = 1;
168             space = 1;
169         }
170     }
171     ParseOtherPerPattern(pattern, len, perSignPos, space, hasSpace);
172 }
173 
IsNoBreakSpace(const char * pattern,const int len,bool order)174 bool NumberData::IsNoBreakSpace(const char *pattern, const int len, bool order)
175 {
176     if (len < 3) { // pattern should at least have 3 bytes
177         return false;
178     }
179     int firstPosition = order ? 2 : (len - 2); // 2 is the offset to find ARABIC_NOBREAK_ONE
180     int secondPosition = order ? 1 : (len - 3); // 3 is the offset to find ARABIC_NOBREAK_TWO
181     if ((static_cast<signed char>(pattern[firstPosition]) == ARABIC_NOBREAK_ONE) &&
182         (static_cast<signed char>(pattern[secondPosition]) == ARABIC_NOBREAK_TWO)) {
183         return true;
184     }
185     return false;
186 }
187 
ParseOtherPerPattern(const char * pattern,const int len,const int perSignPos,const int space,const int hasSpace)188 void NumberData::ParseOtherPerPattern(const char *pattern, const int len, const int perSignPos,
189     const int space, const int hasSpace)
190 {
191     // 2 is the minimal length of pattern
192     if (pattern == nullptr || len < 2) {
193         return;
194     }
195     std::string type;
196     if (perSignPos > 0) {
197         if (perSignPos == 1) {
198             type = "%%%s";
199             if ((hasSpace > 0) && (space == 0)) {
200                 type = "%% %s";
201             } else if ((hasSpace > 0) && (space == 1)) {
202                 unsigned char typeChars[] = { 0x25, 0x25, 0xC2, 0xA0, 0x25, 0x73, 0x0 }; // %%\uc2a0%s
203                 type = reinterpret_cast<char const *>(typeChars);
204             } else {
205                 // do nothing
206             }
207         } else {
208             type = "%s%%";
209             if ((hasSpace > 0) && (space == 0)) {
210                 type = "%s %%";
211             } else if ((hasSpace > 0) && (space == 1)) {
212                 unsigned char typeChars[] = { 0x25, 0x73, 0xC2, 0xA0, 0x25, 0x25, 0x0 }; // %s\uc2a0%%
213                 type = reinterpret_cast<char const *>(typeChars);
214             } else {
215                 // do nothing
216             }
217         }
218     } else {
219         type = "%s%%";
220     }
221     I18nFree(static_cast<void *>(style.entireFormat));
222     int typeLen = type.size();
223     style.entireFormat = I18nNewCharString(type.data(), typeLen);
224 }
225 
SetMinDecimalLength(int length)226 void NumberData::SetMinDecimalLength(int length)
227 {
228     style.minDecimalLength = length;
229 }
230 
NumberData(const char * pat,const char * percentPat,std::string decSign,std::string groupSign,std::string perSign)231 NumberData::NumberData(const char *pat, const char *percentPat, std::string decSign,
232     std::string groupSign, std::string perSign)
233 {
234     if (pat != nullptr || percentPat != nullptr) {
235         std::string nums[NUM_SIZE] = NUMBER_SIGN;
236         SetNumSystem(nums, NUM_SIZE);
237         std::string signs[3] = { decSign, groupSign, perSign }; // use string array contain number data
238         int len = -1;
239         int patLen = -1;
240         if (pat != nullptr) {
241             len = strlen(pat);
242         }
243         if (percentPat != nullptr) {
244             patLen = strlen(percentPat);
245         }
246         Init(pat, len, percentPat, patLen);
247         InitSign(signs, SIGNS_SIZE);
248     }
249 }
250 
NumberData()251 NumberData::NumberData()
252 {
253     isNative = false;
254     std::string signs[3] = { ".", ",", "%" }; // use string array contain number data
255     const char *enNumberPattern = "#,##0.###";
256     const char *percentPattern = "#,##0%";
257     Init(enNumberPattern, strlen(enNumberPattern), percentPattern, strlen(percentPattern));
258     InitSign(signs, SIGNS_SIZE);
259 }
260 
~NumberData()261 NumberData::~NumberData()
262 {
263     I18nFree(static_cast<void *>(group));
264     I18nFree(static_cast<void *>(percent));
265     I18nFree(static_cast<void *>(decimal));
266     I18nFree(static_cast<void *>(numberFormatPattern));
267     I18nFree(static_cast<void *>(percentFormatPattern));
268 }
269 
IsSuccess()270 bool NumberData::IsSuccess()
271 {
272     bool r = isSucc;
273     isSucc = true;
274     return r;
275 }
276 
SetMaxDecimalLength(int length)277 void NumberData::SetMaxDecimalLength(int length)
278 {
279     style.maxDecimalLength = length;
280 }
281 
GetNumberingSystem(const char * numberingSystem,std::string & numberFormatString,std::string & digitsRet)282 void NumberData::GetNumberingSystem(const char *numberingSystem, std::string &numberFormatString,
283     std::string &digitsRet)
284 {
285     numberFormatString = "#,##0.###_#,##0%_._,_%";
286     digitsRet = "0;1;2;3;4;5;6;7;8;9";
287     if (numberingSystem == nullptr || (strcmp(numberingSystem, "latn") == 0)) {
288         return;
289     }
290     if (strcmp(numberingSystem, "arab") == 0) {
291         signed char arabFormatArray[] = {
292             35, 44, 35, 35, 48, 46, 35, 35, 35, 95, 35, 44, 35, 35, 48, 37, -30, -128, -113, 95, -39, -85, 95, -39, -84,
293             95, -39, -86, -40, -100, 0
294         };
295         numberFormatString = reinterpret_cast<char *>(arabFormatArray);
296         signed char localeDigitsArab[] = {
297             -39, -96, 59, -39, -95, 59, -39, -94, 59, -39, -93, 59, -39, -92, 59, -39, -91, 59, -39, -90, 59, -39, -89,
298             59, -39, -88, 59, -39, -87, 0
299         };
300         digitsRet = reinterpret_cast<char *>(localeDigitsArab);
301     } else if (strcmp(numberingSystem, "arabext") == 0) {
302         signed char extFormatArray[] = {
303             35, 44, 35, 35, 48, 46, 35, 35, 35, 95, 35, 44, 35, 35, 48, 37, 95, -39, -85, 95, -39, -84, 95, -39, -86, 0
304         };
305         numberFormatString = reinterpret_cast<char *>(extFormatArray);
306         signed char localeDigitsArabext[] = {
307             -37, -80, 59, -37, -79, 59, -37, -78, 59, -37, -77, 59, -37, -76, 59, -37, -75, 59, -37, -74, 59, -37, -73,
308             59, -37, -72, 59, -37, -71, 0
309         };
310         digitsRet = reinterpret_cast<char *>(localeDigitsArabext);
311     } else if (strcmp(numberingSystem, "beng") == 0) {
312         numberFormatString = "#,##,##0.###_#,##0%_._,_%";
313         signed char localeDigitsBeng[] = {
314             -32, -89, -90, 59, -32, -89, -89, 59, -32, -89, -88, 59, -32, -89, -87, 59, -32, -89, -86, 59, -32, -89,
315             -85, 59, -32, -89, -84, 59, -32, -89, -83, 59, -32, -89, -82, 59, -32, -89, -81, 0
316         };
317         digitsRet = reinterpret_cast<char *>(localeDigitsBeng);
318     } else if (strcmp(numberingSystem, "deva") == 0) {
319         numberFormatString = "#,##,##0.###_#,##,##0%_._,_%";
320         signed char localeDigitsDeva[] = {
321             -32, -91, -90, 59, -32, -91, -89, 59, -32, -91, -88, 59, -32, -91, -87, 59, -32, -91, -86, 59, -32, -91,
322             -85, 59, -32, -91, -84, 59, -32, -91, -83, 59, -32, -91, -82, 59, -32, -91, -81, 0
323         };
324         digitsRet = reinterpret_cast<char *>(localeDigitsDeva);
325     } else if (strcmp(numberingSystem, "mymr") == 0) {
326         signed char localeDigitsMymr[] = {
327             -31, -127, -128, 59, -31, -127, -127, 59, -31, -127, -126, 59, -31, -127, -125, 59, -31, -127, -124, 59,
328             -31, -127, -123, 59, -31, -127, -122, 59, -31, -127, -121, 59, -31, -127, -120, 59, -31, -127, -119, 0
329         };
330         digitsRet = reinterpret_cast<char *>(localeDigitsMymr);
331     } else {
332         // do noting
333     }
334 }
335 
UpdateNumberFormat()336 void NumberData::UpdateNumberFormat()
337 {
338     // reset the style's number pattern which is used to format a decimal number
339     char *format = reinterpret_cast<char *>(I18nMalloc(NUMBER_FORMAT_LENGTH));
340     if (format == nullptr) {
341         isSucc = false;
342         return;
343     }
344     int finalDecLength = GetNumberFormatLength();
345     if (snprintf_s(format, NUMBER_FORMAT_LENGTH, NUMBER_FORMAT_LENGTH - 1, NUMBER_FORMAT, finalDecLength) == -1) {
346         isSucc = false;
347         I18nFree(static_cast<void *>(format));
348         return;
349     }
350     I18nFree(static_cast<void *>(style.numFormat));
351     style.numFormat = format;
352 }
353 
GetNumberFormatLength()354 int NumberData::GetNumberFormatLength()
355 {
356     if (style.minDecimalLength < 0) {
357         if (style.maxDecimalLength < 0) {
358             return style.decLen;
359         }
360         return style.maxDecimalLength;
361     } else {
362         if (style.maxDecimalLength < 0) {
363             return (style.minDecimalLength > style.decLen) ? style.minDecimalLength : style.decLen;
364         } else {
365             return style.maxDecimalLength;
366         }
367     }
368 }
369 
SetMinusSign(const std::string & minus)370 void NumberData::SetMinusSign(const std::string &minus)
371 {
372     this->minusSign = minus;
373 }
374 
GetMinusSign()375 std::string NumberData::GetMinusSign()
376 {
377     return this->minusSign;
378 }
379 
380