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