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((void *)numFormat);
42 I18nFree((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 if (pattern == nullptr || len < 2) {
192 return;
193 }
194 std::string type;
195 if (perSignPos > 0) {
196 if (perSignPos == 1) {
197 type = "%%%s";
198 if ((hasSpace > 0) && (space == 0)) {
199 type = "%% %s";
200 } else if ((hasSpace > 0) && (space == 1)) {
201 unsigned char typeChars[] = { 0x25, 0x25, 0xC2, 0xA0, 0x25, 0x73, 0x0 }; // %%\uc2a0%s
202 type = reinterpret_cast<char const *>(typeChars);
203 } else {
204 // do nothing
205 }
206 } else {
207 type = "%s%%";
208 if ((hasSpace > 0) && (space == 0)) {
209 type = "%s %%";
210 } else if ((hasSpace > 0) && (space == 1)) {
211 unsigned char typeChars[] = { 0x25, 0x73, 0xC2, 0xA0, 0x25, 0x25, 0x0 }; // %s\uc2a0%%
212 type = reinterpret_cast<char const *>(typeChars);
213 } else {
214 // do nothing
215 }
216 }
217 } else {
218 type = "%s%%";
219 }
220 I18nFree((void *)style.entireFormat);
221 int typeLen = type.size();
222 style.entireFormat = I18nNewCharString(type.data(), typeLen);
223 }
224
SetMinDecimalLength(int length)225 void NumberData::SetMinDecimalLength(int length)
226 {
227 style.minDecimalLength = length;
228 }
229
NumberData(const char * pat,const char * percentPat,std::string decSign,std::string groupSign,std::string perSign)230 NumberData::NumberData(const char *pat, const char *percentPat, std::string decSign,
231 std::string groupSign, std::string perSign)
232 {
233 if (pat != nullptr || percentPat != nullptr) {
234 std::string nums[NUM_SIZE] = NUMBER_SIGN;
235 SetNumSystem(nums, NUM_SIZE);
236 std::string signs[3] = { decSign, groupSign, perSign }; // use string array contain number data
237 int len = -1;
238 int patLen = -1;
239 if (pat != nullptr) {
240 len = strlen(pat);
241 }
242 if (percentPat != nullptr) {
243 patLen = strlen(percentPat);
244 }
245 Init(pat, len, percentPat, patLen);
246 InitSign(signs, SIGNS_SIZE);
247 }
248 }
249
NumberData()250 NumberData::NumberData()
251 {
252 isNative = false;
253 std::string signs[3] = { ".", ",", "%" }; // use string array contain number data
254 const char *enNumberPattern = "#,##0.###";
255 const char *percentPattern = "#,##0%";
256 Init(enNumberPattern, strlen(enNumberPattern), percentPattern, strlen(percentPattern));
257 InitSign(signs, SIGNS_SIZE);
258 }
259
~NumberData()260 NumberData::~NumberData()
261 {
262 I18nFree((void *)group);
263 I18nFree((void *)percent);
264 I18nFree((void *)decimal);
265 I18nFree((void *)numberFormatPattern);
266 I18nFree((void *)percentFormatPattern);
267 }
268
IsSuccess()269 bool NumberData::IsSuccess()
270 {
271 bool r = isSucc;
272 isSucc = true;
273 return r;
274 }
275
SetMaxDecimalLength(int length)276 void NumberData::SetMaxDecimalLength(int length)
277 {
278 style.maxDecimalLength = length;
279 }
280
GetNumberingSystem(const char * numberingSystem,std::string & numberFormatString,std::string & digitsRet)281 void NumberData::GetNumberingSystem(const char *numberingSystem, std::string &numberFormatString,
282 std::string &digitsRet)
283 {
284 numberFormatString = "#,##0.###_#,##0%_._,_%";
285 digitsRet = "0;1;2;3;4;5;6;7;8;9";
286 if (numberingSystem == nullptr || (strcmp(numberingSystem, "latn") == 0)) {
287 return;
288 }
289 if (strcmp(numberingSystem, "arab") == 0) {
290 signed char arabFormatArray[] = {
291 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,
292 95, -39, -86, -40, -100, 0
293 };
294 numberFormatString = reinterpret_cast<char *>(arabFormatArray);
295 signed char localeDigitsArab[] = {
296 -39, -96, 59, -39, -95, 59, -39, -94, 59, -39, -93, 59, -39, -92, 59, -39, -91, 59, -39, -90, 59, -39, -89,
297 59, -39, -88, 59, -39, -87, 0
298 };
299 digitsRet = reinterpret_cast<char *>(localeDigitsArab);
300 } else if (strcmp(numberingSystem, "arabext") == 0) {
301 signed char extFormatArray[] = {
302 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
303 };
304 numberFormatString = reinterpret_cast<char *>(extFormatArray);
305 signed char localeDigitsArabext[] = {
306 -37, -80, 59, -37, -79, 59, -37, -78, 59, -37, -77, 59, -37, -76, 59, -37, -75, 59, -37, -74, 59, -37, -73,
307 59, -37, -72, 59, -37, -71, 0
308 };
309 digitsRet = reinterpret_cast<char *>(localeDigitsArabext);
310 } else if (strcmp(numberingSystem, "beng") == 0) {
311 numberFormatString = "#,##,##0.###_#,##0%_._,_%";
312 signed char localeDigitsBeng[] = {
313 -32, -89, -90, 59, -32, -89, -89, 59, -32, -89, -88, 59, -32, -89, -87, 59, -32, -89, -86, 59, -32, -89,
314 -85, 59, -32, -89, -84, 59, -32, -89, -83, 59, -32, -89, -82, 59, -32, -89, -81, 0
315 };
316 digitsRet = reinterpret_cast<char *>(localeDigitsBeng);
317 } else if (strcmp(numberingSystem, "deva") == 0) {
318 numberFormatString = "#,##,##0.###_#,##,##0%_._,_%";
319 signed char localeDigitsDeva[] = {
320 -32, -91, -90, 59, -32, -91, -89, 59, -32, -91, -88, 59, -32, -91, -87, 59, -32, -91, -86, 59, -32, -91,
321 -85, 59, -32, -91, -84, 59, -32, -91, -83, 59, -32, -91, -82, 59, -32, -91, -81, 0
322 };
323 digitsRet = reinterpret_cast<char *>(localeDigitsDeva);
324 } else if (strcmp(numberingSystem, "mymr") == 0) {
325 signed char localeDigitsMymr[] = {
326 -31, -127, -128, 59, -31, -127, -127, 59, -31, -127, -126, 59, -31, -127, -125, 59, -31, -127, -124, 59,
327 -31, -127, -123, 59, -31, -127, -122, 59, -31, -127, -121, 59, -31, -127, -120, 59, -31, -127, -119, 0
328 };
329 digitsRet = reinterpret_cast<char *>(localeDigitsMymr);
330 } else {
331 // do noting
332 }
333 }
334
UpdateNumberFormat()335 void NumberData::UpdateNumberFormat()
336 {
337 // reset the style's number pattern which is used to format a decimal number
338 char *format = reinterpret_cast<char *>(I18nMalloc(NUMBER_FORMAT_LENGTH));
339 if (format == nullptr) {
340 isSucc = false;
341 return;
342 }
343 int finalDecLength = GetNumberFormatLength();
344 if (snprintf_s(format, NUMBER_FORMAT_LENGTH, NUMBER_FORMAT_LENGTH - 1, NUMBER_FORMAT, finalDecLength) == -1) {
345 isSucc = false;
346 I18nFree((void *)format);
347 return;
348 }
349 I18nFree((void *)style.numFormat);
350 style.numFormat = format;
351 }
352
GetNumberFormatLength()353 int NumberData::GetNumberFormatLength()
354 {
355 if (style.minDecimalLength < 0) {
356 if (style.maxDecimalLength < 0) {
357 return style.decLen;
358 }
359 return style.maxDecimalLength;
360 } else {
361 if (style.maxDecimalLength < 0) {
362 return (style.minDecimalLength > style.decLen) ? style.minDecimalLength : style.decLen;
363 } else {
364 return style.maxDecimalLength;
365 }
366 }
367 }
368
SetMinusSign(const std::string & minus)369 void NumberData::SetMinusSign(const std::string &minus)
370 {
371 this->minusSign = minus;
372 }
373
GetMinusSign()374 std::string NumberData::GetMinusSign()
375 {
376 return this->minusSign;
377 }
378
379