• 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     double adjustNum = (num < 0) ? (-1 * num) : num;
133     int len = isPercentDefault ? static_cast<int>(sprintf_s(buff, NUMBER_MAX, "%.f", adjustNum)) :
134         static_cast<int>(sprintf_s(buff, NUMBER_MAX, defaultData->style.numFormat, adjustNum));
135     // convert decimal to char and format
136     if (len < 0) {
137         status = IERROR;
138         return "";
139     }
140     char *decimalNum = strchr(buff, NumberData::NUMBER_DECIMAL);
141     int decLen = (decimalNum == nullptr) ? 0 : strlen(decimalNum);
142     int lastLen = isShowGroup ? (len + CountGroupNum(len - decLen, defaultData->style.isTwoGroup)) : len;
143     char *result = reinterpret_cast<char *>(I18nMalloc(lastLen + 1));
144     if (result == nullptr) {
145         status = IERROR;
146         return "";
147     }
148     result[lastLen] = '\0';
149     bool adjustHasDec = isPercentDefault ? false : hasDec;
150     if (isShowGroup) {
151         char *resultAndContent[] = { result, buff };
152         int lengths[] = { lastLen, len, defaultData->style.isTwoGroup };
153         AddGroup(resultAndContent, lengths, decimalNum, adjustHasDec, decLen);
154     } else {
155         errno_t rc = strcpy_s(result, lastLen + 1, buff);
156         if (rc != EOK) {
157             I18nFree(static_cast<void *>(result));
158             return "";
159         }
160     }
161     // del more zero
162     lastLen = DelMoreZero(defaultData->style, decLen, lastLen, adjustHasDec, result);
163     // if percent
164     if (isPercent && !DealWithPercent(buff, result, status, defaultData->style, lastLen)) {
165         I18nFree(static_cast<void *>(result));
166         return "";
167     }
168     // if have native number to convert
169     std::string outStr = ConvertSignAndNum(result, lastLen, defaultData, defaultData->style);
170     I18nFree(static_cast<void *>(result));
171     if (num < 0) {
172         outStr.insert(0, defaultData->GetMinusSign());
173     }
174     return outStr;
175 }
176 
DealWithPercent(char * buff,char * & result,int & status,StyleData & style,int & lastLen) const177 bool NumberFormatImpl::DealWithPercent(char *buff, char *&result, int &status, StyleData &style, int &lastLen) const
178 {
179     if (style.entireFormat != nullptr) {
180         bool cleanRet = CleanCharArray(buff, NUMBER_MAX);
181         if (!cleanRet) {
182             return false;
183         }
184         int len = static_cast<int>(sprintf_s(buff, NUMBER_MAX, style.entireFormat, result));
185         if (len < 0) {
186             status = IERROR;
187             I18nFree(static_cast<void *>(result));
188             return false;
189         }
190         char *perResult = reinterpret_cast<char *>(I18nMalloc(len + 1));
191         if (perResult == nullptr) {
192             return false;
193         }
194         errno_t rc = strcpy_s(perResult, len + 1, buff);
195         if (rc != EOK) {
196             I18nFree(static_cast<void *>(perResult));
197             return false;
198         }
199         perResult[len] = '\0';
200         lastLen = len;
201         I18nFree(static_cast<void *>(result));
202         result = perResult;
203         perResult = nullptr;
204     }
205     return true;
206 }
207 
208 
DelMoreZero(const StyleData & style,int decLen,int lastLen,bool hasDec,char * & result) const209 int NumberFormatImpl::DelMoreZero(const StyleData &style, int decLen, int lastLen, bool hasDec, char *&result) const
210 {
211     int num = 0;
212     if (decLen > 1) {
213         int delNum = decLen - 1;
214         num = DelZero(result, lastLen, delNum, true);
215     }
216     // delete more char
217     if ((maxDecimalLength != NO_SET) && (maxDecimalLength < decLen - 1 - num)) {
218         int delNum = decLen - 1 - num - maxDecimalLength;
219         num = num + DelZero(result, lastLen - num, delNum, false);
220     }
221     // fill zero to min
222     if (hasDec && (minDecimalLength != NO_SET) && (minDecimalLength > decLen - 1 - num)) {
223         if (decLen - 1 - num < 0) {
224             int add = minDecimalLength + 1;
225             char *tempResult = FillMinDecimal(result, lastLen - num, add, false);
226             if (result != nullptr) {
227 #ifdef I18N_PRODUCT
228                 (void)OhosFree(static_cast<void *>(result));
229 #else
230                 (void)free(result);
231 #endif
232             }
233             result = tempResult;
234             num = num - add;
235         } else {
236             int add = minDecimalLength - decLen + num + 1;
237             char *tempResult = FillMinDecimal(result, lastLen - num, add, true);
238             if (result != nullptr) {
239 #ifdef I18N_PRODUCT
240                 (void)OhosFree(static_cast<void *>(result));
241 #else
242                 (void)free(result);
243 #endif
244             }
245             result = tempResult;
246             num = num - add;
247         }
248     }
249     return lastLen - num;
250 }
251 
CheckStatus(const errno_t rc,int & status) const252 void NumberFormatImpl::CheckStatus(const errno_t rc, int &status) const
253 {
254     if (rc != EOK) {
255         status = IERROR;
256     }
257 }
258 
CountGroupNum(int intLength,bool isTwoGrouped) const259 int NumberFormatImpl::CountGroupNum(int intLength, bool isTwoGrouped) const
260 {
261     int groupNum;
262     if (!isTwoGrouped) {
263         groupNum = static_cast<int>(intLength / NumberData::NUMBER_GROUP);
264         if ((intLength % NumberData::NUMBER_GROUP) == 0) {
265             --groupNum;
266         }
267     } else {
268         if (intLength <= NumberData::NUMBER_GROUP) {
269             return 0;
270         }
271         intLength -= NumberData::NUMBER_GROUP;
272         groupNum = 1 + static_cast<int>(intLength / NumberData::TWO_GROUP);
273         if ((intLength % NumberData::TWO_GROUP) == 0) {
274             --groupNum;
275         }
276     }
277     return groupNum;
278 }
279 
AddGroup(char * targetAndSource[],const int len[],const char * decimal,bool hasDec,int decLen) const280 void NumberFormatImpl::AddGroup(char *targetAndSource[], const int len[], const char *decimal,
281     bool hasDec, int decLen) const
282 {
283     // The len array must have at least 3 elements and the targetAndSource array
284     // must have at least 2 elements.
285     if ((targetAndSource == nullptr) || (len == nullptr)) {
286         return;
287     }
288     char *target = targetAndSource[0]; // use array to store target and source string, first is target string
289     int targetLen = len[0]; // use array to store target length and source length, first is target length
290     char *source = targetAndSource[1]; // use array to store target and source string, second is source string
291     int sourceLen = len[1]; // use array to store target length and source length, second is source length
292     int isTwoGroup = len[2]; // 2 is the index of group info
293     int intLen = sourceLen - decLen;
294     int addIndex = 0;
295     for (int i = 0; (i < intLen) && (addIndex < targetLen); i++, addIndex++) {
296         int index = intLen - i;
297         // ADD GROUP SIGN
298         if (isTwoGroup == 0) {
299             if ((index % NumberData::NUMBER_GROUP == 0) && (i != 0)) {
300                 target[addIndex] = ',';
301                 addIndex++;
302             }
303             target[addIndex] = source[i];
304         } else {
305             if ((index == NumberData::NUMBER_GROUP) && (i != 0)) {
306                 target[addIndex] = ',';
307                 addIndex++;
308                 target[addIndex] = source[i];
309             } else if ((index > NumberData::NUMBER_GROUP) &&
310                 ((index - NumberData::NUMBER_GROUP) % NumberData::TWO_GROUP == 0) && (i != 0)) {
311                 target[addIndex] = ',';
312                 addIndex++;
313                 target[addIndex] = source[i];
314             } else {
315                 target[addIndex] = source[i];
316             }
317         }
318     }
319     if (decLen > 0) {
320         target[addIndex] = hasDec ? '.' : '\0';
321         for (int j = 1; (j < decLen) && (addIndex < targetLen); j++) {
322             target[addIndex + j] = hasDec ? decimal[j] : '\0';
323         }
324     }
325 }
326 
DelZero(char * target,int len,int delNum,bool onlyZero) const327 int NumberFormatImpl::DelZero(char *target, int len, int delNum, bool onlyZero) const
328 {
329     int num = 0;
330     for (int i = len - 1; (i > len - delNum - 1) && (i >= 0); i--) {
331         if ((target[i] != '0') && onlyZero) {
332             break;
333         }
334         target[i] = '\0';
335         num++;
336         if ((i - 1 > 0) && (target[i - 1] == '.')) {
337             target[i - 1] = '\0';
338             num++;
339             break;
340         }
341     }
342     return num;
343 }
344 
Format(double num,NumberFormatType type,int & status) const345 std::string NumberFormatImpl::Format(double num, NumberFormatType type, int &status) const
346 {
347     if (defaultData == nullptr) {
348         status = IERROR;
349         return "";
350     }
351     if (type == PERCENT) { // percent,the decimal needs to be multiplied by 100.
352         return InnerFormat(num * 100, true, true, true, status);
353     } else {
354         return InnerFormat(num, true, true, false, status);
355     }
356 }
357 
Format(int num,int & status) const358 std::string NumberFormatImpl::Format(int num, int &status) const
359 {
360     if (defaultData == nullptr) {
361         status = IERROR;
362         return "";
363     }
364     return InnerFormat(num, false, true, false, status);
365 }
366 
FormatNoGroup(double num,NumberFormatType type,int & status) const367 std::string NumberFormatImpl::FormatNoGroup(double num, NumberFormatType type, int &status) const
368 {
369     if (defaultData == nullptr) {
370         status = IERROR;
371         return "";
372     }
373     if (type == PERCENT) { // percent,the decimal needs to be multiplied by 100.
374         return InnerFormat(num * 100, true, false, true, status);
375     } else {
376         return InnerFormat(num, true, false, false, status);
377     }
378 }
379 
FormatNoGroup(int num,int & status) const380 std::string NumberFormatImpl::FormatNoGroup(int num, int &status) const
381 {
382     if (defaultData == nullptr) {
383         status = IERROR;
384         return "";
385     }
386     return InnerFormat(num, false, false, false, status);
387 }
388 
SetMaxDecimalLength(int length)389 bool NumberFormatImpl::SetMaxDecimalLength(int length)
390 {
391     if (defaultData == nullptr) {
392         return false;
393     }
394     int adjustValue = (length < 0) ? -1 : length;
395     if ((minDecimalLength >= 0) && (minDecimalLength > adjustValue)) {
396         minDecimalLength = adjustValue;
397         defaultData->SetMinDecimalLength(adjustValue);
398     }
399     maxDecimalLength = adjustValue;
400     defaultData->SetMaxDecimalLength(length);
401     defaultData->UpdateNumberFormat();
402     return true;
403 }
404 
SetMinDecimalLength(int length)405 bool NumberFormatImpl::SetMinDecimalLength(int length)
406 {
407     if (defaultData == nullptr) {
408         return false;
409     }
410     int adjustValue = (length < 0) ? -1 : length;
411     if ((maxDecimalLength >= 0) && (maxDecimalLength < adjustValue)) {
412         maxDecimalLength = adjustValue;
413         defaultData->SetMaxDecimalLength(maxDecimalLength);
414     }
415     minDecimalLength = adjustValue;
416     defaultData->SetMinDecimalLength(adjustValue);
417     defaultData->UpdateNumberFormat();
418     return true;
419 }
420 
FillMinDecimal(const char * target,int len,int addSize,bool isDec) const421 char *NumberFormatImpl::FillMinDecimal(const char *target, int len, int addSize, bool isDec) const
422 {
423     char *content = I18nNewCharString(target, len + addSize);
424     if (content == nullptr) {
425         return nullptr;
426     }
427     for (int i = 0; i < addSize; i++) {
428         if ((!isDec) && (i == 0)) {
429             content[len + i] = '.';
430             continue;
431         }
432         content[len + i] = '0';
433     }
434     return content;
435 }
436