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