• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "number_format_impl.h"
17 #include "i18n_memory_adapter.h"
18 #include "number_data.h"
19 #include "str_util.h"
20 
21 using namespace OHOS::I18N;
22 
ConvertSignAndNum(const char * content,int len,NumberData * data,StyleData & style) const23 std::string NumberFormatImpl::ConvertSignAndNum(const char *content, int len, NumberData *data, StyleData &style) const
24 {
25     std::string strContent = content;
26     int off = 0;
27     for (int i = 0; i < len; i++) {
28         switch (content[i]) {
29             case NumberData::NUMBER_DECIMAL:
30                 off = ReplaceAndCountOff(strContent, i + off, data->decimal, off);
31                 break;
32             case NumberData::NUMBER_GROUPSIGN:
33                 off = ReplaceAndCountOff(strContent, i + off, data->group, off);
34                 break;
35             case NumberData::NUMBER_PERCENT:
36                 off = ReplaceAndCountOff(strContent, i + off, data->percent, off);
37                 break;
38             default:
39                 break;
40         }
41         if (defaultData->isNative) {
42             off = ConvertNum(strContent, content[i], data, i, off);
43         }
44     }
45     return strContent;
46 }
47 
ConvertNum(std::string & strContent,char currentChar,const NumberData * data,int index,int off) const48 int NumberFormatImpl::ConvertNum(std::string &strContent, char currentChar,
49     const NumberData *data, int index, int off) const
50 {
51     std::string numStr = "0123456789";
52     size_t charPos = numStr.find(currentChar);
53     return (charPos != std::string::npos) ?
54         ReplaceAndCountOff(strContent, index + off, data->nativeNums[charPos].c_str(), off) : off;
55 }
56 
NumberFormatImpl(LocaleInfo & locale,int & status)57 NumberFormatImpl::NumberFormatImpl(LocaleInfo &locale, int &status)
58 {
59     if (locale.GetId() == nullptr) {
60         status = IERROR;
61         return;
62     }
63     mLocale = locale;
64 }
65 
Init(const DataResource & resource)66 bool NumberFormatImpl::Init(const DataResource &resource)
67 {
68     std::string numebrSystemFormat;
69     std::string unprocessedNumberFormat = resource.GetString(DataResourceType::NUMBER_FORMAT);
70     std::string unprocessedNumberDigit = resource.GetString(DataResourceType::NUMBER_DIGIT);
71     std::string split[NUM_PATTERN_SIZE];
72     Split(unprocessedNumberFormat, split, NUM_PATTERN_SIZE, NUM_PATTERN_SEP);
73     std::string decSign = split[NUM_DEC_SIGN_INDEX];
74     std::string groupSign = split[NUM_GROUP_SIGN_INDEX];
75     std::string perSign = split[NUM_PERCENT_SIGN_INDEX];
76     const char *numberDigits = mLocale.GetExtension("nu");
77     if (numberDigits != nullptr) {
78         NumberData::GetNumberingSystem(numberDigits, numebrSystemFormat, unprocessedNumberDigit);
79         std::string temp[NUM_PATTERN_SIZE];
80         Split(numebrSystemFormat, temp, NUM_PATTERN_SIZE, NUM_PATTERN_SEP);
81         decSign = temp[NUM_DEC_SIGN_INDEX];
82         groupSign = temp[NUM_GROUP_SIGN_INDEX];
83         perSign = temp[NUM_PERCENT_SIGN_INDEX];
84     }
85     std::string origin = split[NUM_PERCENT_PAT_INDEX];
86     const char *pat = split[NUM_PAT_INDEX].c_str();
87     int size = origin.size();
88     std::string adjust = origin;
89     // strip "0x80 0xe2 0x8f" these three bytes in pat
90     if (size >= 3 && // check the last 3 character
91         (static_cast<unsigned char>(origin.at(size - 1)) == 0x8f) && // check whether the last one is 0x8f
92         (static_cast<unsigned char>(origin.at(size - 2)) == 0x80) && // check whether the index of size - 2 is 0x80
93         (static_cast<unsigned char>(origin.at(size - 3)) == 0xe2)) { // check whether the index of size - 3 is 0xe2
94         adjust = std::string(origin, 0, size - 3); // strip the last 3 chars
95     }
96     const char *percentPat = adjust.c_str();
97     defaultData = new(std::nothrow) NumberData(pat, percentPat, decSign, groupSign, perSign);
98     if (defaultData == nullptr) {
99         return false;
100     }
101     if (unprocessedNumberDigit != "") {
102         std::string splitDigit[NUM_DIGIT_SIZE];
103         Split(unprocessedNumberDigit, splitDigit, NUM_DIGIT_SIZE, NUM_DIGIT_SEP);
104         defaultData->SetNumSystem(splitDigit, NUM_DIGIT_SIZE);
105     }
106     // set minus sign
107     std::string minus = resource.GetString(DataResourceType::MINUS_SIGN);
108     defaultData->SetMinusSign(minus);
109     return true;
110 }
111 
112 
~NumberFormatImpl()113 NumberFormatImpl::~NumberFormatImpl()
114 {
115     if (defaultData != nullptr) {
116         delete defaultData;
117         defaultData = nullptr;
118     }
119 }
120 
InnerFormat(double num,bool hasDec,bool isShowGroup,bool isPercent,int & status) const121 std::string NumberFormatImpl::InnerFormat(double num, bool hasDec, bool isShowGroup, bool isPercent,
122     int &status) const
123 {
124     if (defaultData == nullptr) {
125         return "";
126     }
127     char buff[NUMBER_MAX] = { 0 };
128     bool isPercentDefault = isPercent && (defaultData->style.minDecimalLength < 0);
129     int len;
130     double adjustNum = (num < 0) ? (-1 * num) : num;
131     if (isPercentDefault) {
132         len = static_cast<int>(sprintf_s(buff, NUMBER_MAX, "%.f", adjustNum));
133     } else {
134         len = static_cast<int>(sprintf_s(buff, NUMBER_MAX, defaultData->style.numFormat, adjustNum));
135     }
136     // convert decimal to char and format
137     if (len < 0) {
138         status = IERROR;
139         return "";
140     }
141     char *decimalNum = strchr(buff, NumberData::NUMBER_DECIMAL);
142     int decLen = (decimalNum == nullptr) ? 0 : strlen(decimalNum);
143     int adjustIntLength = len - decLen;
144     int lastLen = isShowGroup ? (len + CountGroupNum(adjustIntLength, defaultData->style.isTwoGroup)) : len;
145     char *result = reinterpret_cast<char *>(I18nMalloc(lastLen + 1));
146     if (result == nullptr) {
147         status = IERROR;
148         return "";
149     }
150     result[lastLen] = '\0';
151     bool adjustHasDec = isPercentDefault ? false : hasDec;
152     if (isShowGroup) {
153         char *resultAndContent[] = { result, buff };
154         int lengths[] = { lastLen, len, defaultData->style.isTwoGroup };
155         AddGroup(resultAndContent, lengths, decimalNum, adjustHasDec, decLen);
156     } else {
157         errno_t rc = strcpy_s(result, lastLen + 1, buff);
158         if (rc != EOK) {
159             I18nFree((void *)result);
160             return "";
161         }
162     }
163     // del more zero
164     lastLen = DelMoreZero(defaultData->style, decLen, lastLen, adjustHasDec, result);
165     // if percent
166     if (isPercent && !DealWithPercent(buff, result, status, defaultData->style, lastLen)) {
167         I18nFree((void *)result);
168         return "";
169     }
170     // if have native number to convert
171     std::string outStr = ConvertSignAndNum(result, lastLen, defaultData, defaultData->style);
172     I18nFree((void *)result);
173     if (num < 0) {
174         outStr.insert(0, defaultData->GetMinusSign());
175     }
176     return outStr;
177 }
178 
DealWithPercent(char * buff,char * & result,int & status,StyleData & style,int & lastLen) const179 bool NumberFormatImpl::DealWithPercent(char *buff, char *&result, int &status, StyleData &style, int &lastLen) const
180 {
181     if (style.entireFormat != nullptr) {
182         bool cleanRet = CleanCharArray(buff, NUMBER_MAX);
183         if (!cleanRet) {
184             return false;
185         }
186         int len = static_cast<int>(sprintf_s(buff, NUMBER_MAX, style.entireFormat, result));
187         if (len < 0) {
188             status = IERROR;
189             I18nFree((void *)result);
190             return false;
191         }
192         char *perResult = reinterpret_cast<char *>(I18nMalloc(len + 1));
193         if (perResult == nullptr) {
194             return false;
195         }
196         errno_t rc = strcpy_s(perResult, len + 1, buff);
197         if (rc != EOK) {
198             I18nFree((void *)perResult);
199             return false;
200         }
201         perResult[len] = '\0';
202         lastLen = len;
203         I18nFree((void *)result);
204         result = perResult;
205         perResult = nullptr;
206     }
207     return true;
208 }
209 
210 
DelMoreZero(const StyleData & style,int decLen,int lastLen,bool hasDec,char * & result) const211 int NumberFormatImpl::DelMoreZero(const StyleData &style, int decLen, int lastLen, bool hasDec, char *&result) const
212 {
213     int num = 0;
214     if (decLen > 1) {
215         int delNum = decLen - 1;
216         num = DelZero(result, lastLen, delNum, true);
217     }
218     // delete more char
219     if ((maxDecimalLength != NO_SET) && (maxDecimalLength < decLen - 1 - num)) {
220         int delNum = decLen - 1 - num - maxDecimalLength;
221         num = num + DelZero(result, lastLen - num, delNum, false);
222     }
223     // fill zero to min
224     if (hasDec && (minDecimalLength != NO_SET) && (minDecimalLength > decLen - 1 - num)) {
225         if (decLen - 1 - num < 0) {
226             int add = minDecimalLength + 1;
227             char *tempResult = FillMinDecimal(result, lastLen - num, add, false);
228             if (result != nullptr) {
229 #ifdef I18N_PRODUCT
230                 (void)OhosFree((void *) result);
231 #else
232                 (void)free(result);
233 #endif
234             }
235             result = tempResult;
236             num = num - add;
237         } else {
238             int add = minDecimalLength - decLen + num + 1;
239             char *tempResult = FillMinDecimal(result, lastLen - num, add, true);
240             if (result != nullptr) {
241 #ifdef I18N_PRODUCT
242                 (void)OhosFree((void *) result);
243 #else
244                 (void)free(result);
245 #endif
246             }
247             result = tempResult;
248             num = num - add;
249         }
250     }
251     return lastLen - num;
252 }
253 
CheckStatus(const errno_t rc,int & status) const254 void NumberFormatImpl::CheckStatus(const errno_t rc, int &status) const
255 {
256     if (rc != EOK) {
257         status = IERROR;
258     }
259 }
260 
CountGroupNum(int intLength,bool isTwoGrouped) const261 int NumberFormatImpl::CountGroupNum(int intLength, bool isTwoGrouped) const
262 {
263     int groupNum;
264     if (!isTwoGrouped) {
265         groupNum = static_cast<int>(intLength / NumberData::NUMBER_GROUP);
266         if ((intLength % NumberData::NUMBER_GROUP) == 0) {
267             --groupNum;
268         }
269     } else {
270         if (intLength <= NumberData::NUMBER_GROUP) {
271             return 0;
272         }
273         intLength -= NumberData::NUMBER_GROUP;
274         groupNum = 1 + static_cast<int>(intLength / NumberData::TWO_GROUP);
275         if ((intLength % NumberData::TWO_GROUP) == 0) {
276             --groupNum;
277         }
278     }
279     return groupNum;
280 }
281 
AddGroup(char * targetAndSource[],const int len[],const char * decimal,bool hasDec,int decLen) const282 void NumberFormatImpl::AddGroup(char *targetAndSource[], const int len[], const char *decimal,
283     bool hasDec, int decLen) const
284 {
285     // The len array must have at least 3 elements and the targetAndSource array
286     // must have at least 2 elements.
287     if ((targetAndSource == nullptr) || (len == nullptr)) {
288         return;
289     }
290     char *target = targetAndSource[0]; // use array to store target and source string, first is target string
291     int targetLen = len[0]; // use array to store target length and source length, first is target length
292     char *source = targetAndSource[1]; // use array to store target and source string, second is source string
293     int sourceLen = len[1]; // use array to store target length and source length, second is source length
294     int isTwoGroup = len[2]; // 2 is the index of group info
295     int intLen = sourceLen - decLen;
296     int addIndex = 0;
297     for (int i = 0; (i < intLen) && (addIndex < targetLen); i++, addIndex++) {
298         int index = intLen - i;
299         // ADD GROUP SIGN
300         if (isTwoGroup == 0) {
301             if ((index % NumberData::NUMBER_GROUP == 0) && (i != 0)) {
302                 target[addIndex] = ',';
303                 addIndex++;
304             }
305             target[addIndex] = source[i];
306         } else {
307             if ((index == NumberData::NUMBER_GROUP) && (i != 0)) {
308                 target[addIndex] = ',';
309                 addIndex++;
310                 target[addIndex] = source[i];
311             } else if ((index > NumberData::NUMBER_GROUP) &&
312                 ((index - NumberData::NUMBER_GROUP) % NumberData::TWO_GROUP == 0) && (i != 0)) {
313                 target[addIndex] = ',';
314                 addIndex++;
315                 target[addIndex] = source[i];
316             } else {
317                 target[addIndex] = source[i];
318             }
319         }
320     }
321     if (decLen > 0) {
322         target[addIndex] = hasDec ? '.' : '\0';
323         for (int j = 1; (j < decLen) && (addIndex < targetLen); j++) {
324             target[addIndex + j] = hasDec ? decimal[j] : '\0';
325         }
326     }
327 }
328 
DelZero(char * target,int len,int delNum,bool onlyZero) const329 int NumberFormatImpl::DelZero(char *target, int len, int delNum, bool onlyZero) const
330 {
331     int num = 0;
332     for (int i = len - 1; (i > len - delNum - 1) && (i >= 0); i--) {
333         if ((target[i] != '0') && onlyZero) {
334             break;
335         }
336         target[i] = '\0';
337         num++;
338         if ((i - 1 > 0) && (target[i - 1] == '.')) {
339             target[i - 1] = '\0';
340             num++;
341             break;
342         }
343     }
344     return num;
345 }
346 
Format(double num,NumberFormatType type,int & status) const347 std::string NumberFormatImpl::Format(double num, NumberFormatType type, int &status) const
348 {
349     if (defaultData == nullptr) {
350         status = IERROR;
351         return "";
352     }
353     if (type == PERCENT) { // percent,the decimal needs to be multiplied by 100.
354         return InnerFormat(num * 100, true, true, true, status);
355     } else {
356         return InnerFormat(num, true, true, false, status);
357     }
358 }
359 
Format(int num,int & status) const360 std::string NumberFormatImpl::Format(int num, int &status) const
361 {
362     if (defaultData == nullptr) {
363         status = IERROR;
364         return "";
365     }
366     return InnerFormat(num, false, true, false, status);
367 }
368 
FormatNoGroup(double num,NumberFormatType type,int & status) const369 std::string NumberFormatImpl::FormatNoGroup(double num, NumberFormatType type, int &status) const
370 {
371     if (defaultData == nullptr) {
372         status = IERROR;
373         return "";
374     }
375     if (type == PERCENT) { // percent,the decimal needs to be multiplied by 100.
376         return InnerFormat(num * 100, true, false, true, status);
377     } else {
378         return InnerFormat(num, true, false, false, status);
379     }
380 }
381 
FormatNoGroup(int num,int & status) const382 std::string NumberFormatImpl::FormatNoGroup(int num, int &status) const
383 {
384     if (defaultData == nullptr) {
385         status = IERROR;
386         return "";
387     }
388     return InnerFormat(num, false, false, false, status);
389 }
390 
SetMaxDecimalLength(int length)391 bool NumberFormatImpl::SetMaxDecimalLength(int length)
392 {
393     if (defaultData == nullptr) {
394         return false;
395     }
396     int adjustValue = (length < 0) ? -1 : length;
397     if ((minDecimalLength >= 0) && (minDecimalLength > adjustValue)) {
398         minDecimalLength = adjustValue;
399         defaultData->SetMinDecimalLength(adjustValue);
400     }
401     maxDecimalLength = adjustValue;
402     defaultData->SetMaxDecimalLength(length);
403     defaultData->UpdateNumberFormat();
404     return true;
405 }
406 
SetMinDecimalLength(int length)407 bool NumberFormatImpl::SetMinDecimalLength(int length)
408 {
409     if (defaultData == nullptr) {
410         return false;
411     }
412     int adjustValue = (length < 0) ? -1 : length;
413     if ((maxDecimalLength >= 0) && (maxDecimalLength < adjustValue)) {
414         maxDecimalLength = adjustValue;
415         defaultData->SetMaxDecimalLength(maxDecimalLength);
416     }
417     minDecimalLength = adjustValue;
418     defaultData->SetMinDecimalLength(adjustValue);
419     defaultData->UpdateNumberFormat();
420     return true;
421 }
422 
FillMinDecimal(const char * target,int len,int addSize,bool isDec) const423 char *NumberFormatImpl::FillMinDecimal(const char *target, int len, int addSize, bool isDec) const
424 {
425     char *content = I18nNewCharString(target, len + addSize);
426     if (content == nullptr) {
427         return nullptr;
428     }
429     for (int i = 0; i < addSize; i++) {
430         if ((!isDec) && (i == 0)) {
431             content[len + i] = '.';
432             continue;
433         }
434         content[len + i] = '0';
435     }
436     return content;
437 }
438