1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include <algorithm>
8 
9 #include "core/include/fxcrt/fx_xml.h"
10 #include "xfa/src/fgas/src/fgas_base.h"
11 #include "fx_localeimp.h"
12 
13 #define FX_LOCALECATEGORY_DateHash 0xbde9abde
14 #define FX_LOCALECATEGORY_TimeHash 0x2d71b00f
15 #define FX_LOCALECATEGORY_DateTimeHash 0x158c72ed
16 #define FX_LOCALECATEGORY_NumHash 0x0b4ff870
17 #define FX_LOCALECATEGORY_TextHash 0x2d08af85
18 #define FX_LOCALECATEGORY_ZeroHash 0x568cb500
19 #define FX_LOCALECATEGORY_NullHash 0x052931bb
20 typedef struct _FX_LOCALESUBCATEGORYINFO {
21   uint32_t uHash;
22   const FX_WCHAR* pName;
23   int32_t eSubCategory;
24 } FX_LOCALESUBCATEGORYINFO, *FX_LPLOCALESUBCATEGORYINFO;
25 typedef FX_LOCALESUBCATEGORYINFO const* FX_LPCLOCALESUBCATEGORYINFO;
26 const static FX_LOCALESUBCATEGORYINFO g_FXLocaleDateTimeSubCatData[] = {
27     {0x14da2125, L"default", FX_LOCALEDATETIMESUBCATEGORY_Default},
28     {0x9041d4b0, L"short", FX_LOCALEDATETIMESUBCATEGORY_Short},
29     {0xa084a381, L"medium", FX_LOCALEDATETIMESUBCATEGORY_Medium},
30     {0xcdce56b3, L"full", FX_LOCALEDATETIMESUBCATEGORY_Full},
31     {0xf6b4afb0, L"long", FX_LOCALEDATETIMESUBCATEGORY_Long},
32 };
33 const static int32_t g_iFXLocaleDateTimeSubCatCount =
34     sizeof(g_FXLocaleDateTimeSubCatData) / sizeof(FX_LOCALESUBCATEGORYINFO);
35 const static FX_LOCALESUBCATEGORYINFO g_FXLocaleNumSubCatData[] = {
36     {0x46f95531, L"percent", FX_LOCALENUMPATTERN_Percent},
37     {0x4c4e8acb, L"currency", FX_LOCALENUMPATTERN_Currency},
38     {0x54034c2f, L"decimal", FX_LOCALENUMPATTERN_Decimal},
39     {0x7568e6ae, L"integer", FX_LOCALENUMPATTERN_Integer},
40 };
41 const static int32_t g_iFXLocaleNumSubCatCount =
42     sizeof(g_FXLocaleNumSubCatData) / sizeof(FX_LOCALESUBCATEGORYINFO);
43 typedef struct _FX_LOCALETIMEZONEINFO {
44   FX_DWORD uHash;
45   int16_t iHour;
46   int16_t iMinute;
47 } FX_LOCALETIMEZONEINFO, *FX_LPLOCALETIMEZONEINFO;
48 typedef FX_LOCALETIMEZONEINFO const* FX_LPCLOCALETIMEZONEINFO;
49 const static FX_LOCALETIMEZONEINFO g_FXLocaleTimeZoneData[] = {
50     {FXBSTR_ID(0, 'C', 'D', 'T'), -5, 0}, {FXBSTR_ID(0, 'C', 'S', 'T'), -6, 0},
51     {FXBSTR_ID(0, 'E', 'D', 'T'), -4, 0}, {FXBSTR_ID(0, 'E', 'S', 'T'), -5, 0},
52     {FXBSTR_ID(0, 'M', 'D', 'T'), -6, 0}, {FXBSTR_ID(0, 'M', 'S', 'T'), -7, 0},
53     {FXBSTR_ID(0, 'P', 'D', 'T'), -7, 0}, {FXBSTR_ID(0, 'P', 'S', 'T'), -8, 0},
54 };
55 const static int32_t g_iFXLocaleTimeZoneCount =
56     sizeof(g_FXLocaleTimeZoneData) / sizeof(FX_LOCALETIMEZONEINFO);
57 const static CFX_WideStringC gs_wsTextSymbols = FX_WSTRC(L"AXO09");
58 const static CFX_WideStringC gs_wsTimeSymbols = FX_WSTRC(L"hHkKMSFAzZ");
59 const static CFX_WideStringC gs_wsDateSymbols = FX_WSTRC(L"DJMEeGgYwW");
60 const static CFX_WideStringC gs_wsConstChars = FX_WSTRC(L",-:/. ");
FX_Local_Find(const CFX_WideStringC & wsSymbols,FX_WCHAR ch,FX_STRSIZE nStart=0)61 static FX_STRSIZE FX_Local_Find(const CFX_WideStringC& wsSymbols,
62                                 FX_WCHAR ch,
63                                 FX_STRSIZE nStart = 0) {
64   FX_STRSIZE nLength = wsSymbols.GetLength();
65   if (nLength < 1 || nStart > nLength) {
66     return -1;
67   }
68   const FX_WCHAR* lpsz =
69       (const FX_WCHAR*)FXSYS_wcschr(wsSymbols.GetPtr() + nStart, ch);
70   return (lpsz == NULL) ? -1 : (FX_STRSIZE)(lpsz - wsSymbols.GetPtr());
71 }
72 static const FX_WCHAR* const gs_LocalNumberSymbols[] = {
73     L"decimal", L"grouping",       L"percent",      L"minus",
74     L"zero",    L"currencySymbol", L"currencyName",
75 };
Create(CXML_Element * pLocaleData)76 IFX_Locale* IFX_Locale::Create(CXML_Element* pLocaleData) {
77   return new CFX_Locale(pLocaleData);
78 }
CFX_Locale(CXML_Element * pLocaleData)79 CFX_Locale::CFX_Locale(CXML_Element* pLocaleData) {
80   m_pElement = pLocaleData;
81 }
~CFX_Locale()82 CFX_Locale::~CFX_Locale() {}
GetName()83 CFX_WideString CFX_Locale::GetName() {
84   return CFX_WideString();
85 }
FX_GetXMLContent(const CFX_ByteStringC & bsSpace,CXML_Element * pxmlElement,const CFX_ByteStringC & bsTag,const CFX_WideStringC & wsName)86 static CFX_WideString FX_GetXMLContent(const CFX_ByteStringC& bsSpace,
87                                        CXML_Element* pxmlElement,
88                                        const CFX_ByteStringC& bsTag,
89                                        const CFX_WideStringC& wsName) {
90   CXML_Element* pDatePattern = NULL;
91   int32_t nCount = pxmlElement->CountElements(bsSpace, bsTag);
92   int32_t i = 0;
93   for (; i < nCount; i++) {
94     pDatePattern = pxmlElement->GetElement(bsSpace, bsTag, i);
95     if (pDatePattern->GetAttrValue("name") == wsName) {
96       break;
97     }
98   }
99   if (i < nCount && pDatePattern) {
100     return pDatePattern->GetContent(0);
101   }
102   return L"";
103 }
GetNumbericSymbol(FX_LOCALENUMSYMBOL eType,CFX_WideString & wsNumSymbol) const104 void CFX_Locale::GetNumbericSymbol(FX_LOCALENUMSYMBOL eType,
105                                    CFX_WideString& wsNumSymbol) const {
106   if (!m_pElement) {
107     return;
108   }
109   CFX_ByteString bsSpace;
110   CFX_WideString wsName = gs_LocalNumberSymbols[eType];
111   CXML_Element* pNumberSymbols =
112       m_pElement->GetElement(bsSpace, "numberSymbols");
113   if (!pNumberSymbols) {
114     return;
115   }
116   wsNumSymbol =
117       FX_GetXMLContent(bsSpace, pNumberSymbols, "numberSymbol", wsName);
118 }
GetDateTimeSymbols(CFX_WideString & wsDtSymbol) const119 void CFX_Locale::GetDateTimeSymbols(CFX_WideString& wsDtSymbol) const {
120   if (!m_pElement) {
121     return;
122   }
123   CFX_ByteString bsSpace;
124   CXML_Element* pNumberSymbols =
125       m_pElement->GetElement(bsSpace, "dateTimeSymbols");
126   if (!pNumberSymbols) {
127     return;
128   }
129   wsDtSymbol = pNumberSymbols->GetContent(0);
130 }
FX_GetCalendarSymbol(CXML_Element * pXmlElement,const CFX_ByteString & symbol_type,int32_t index,FX_BOOL bAbbr,CFX_WideString & wsName)131 static void FX_GetCalendarSymbol(CXML_Element* pXmlElement,
132                                  const CFX_ByteString& symbol_type,
133                                  int32_t index,
134                                  FX_BOOL bAbbr,
135                                  CFX_WideString& wsName) {
136   CFX_ByteString bsSpace;
137   CFX_ByteString pstrSymbolNames = symbol_type + "Names";
138   CXML_Element* pChild = pXmlElement->GetElement(bsSpace, "calendarSymbols");
139   if (!pChild) {
140     return;
141   }
142   CXML_Element* pSymbolNames = pChild->GetElement(bsSpace, pstrSymbolNames);
143   if (!pSymbolNames) {
144     return;
145   }
146   if (pSymbolNames->GetAttrInteger("abbr") != bAbbr) {
147     pSymbolNames = pChild->GetElement(bsSpace, pstrSymbolNames, 1);
148   }
149   if (pSymbolNames && pSymbolNames->GetAttrInteger("abbr") == bAbbr) {
150     CXML_Element* pSymbolName =
151         pSymbolNames->GetElement(bsSpace, symbol_type, index);
152     if (pSymbolName) {
153       wsName = pSymbolName->GetContent(0);
154     }
155   }
156 }
GetMonthName(int32_t nMonth,CFX_WideString & wsMonthName,FX_BOOL bAbbr) const157 void CFX_Locale::GetMonthName(int32_t nMonth,
158                               CFX_WideString& wsMonthName,
159                               FX_BOOL bAbbr) const {
160   if (!m_pElement) {
161     return;
162   }
163   FX_GetCalendarSymbol(m_pElement, "month", nMonth, bAbbr, wsMonthName);
164 }
GetDayName(int32_t nWeek,CFX_WideString & wsDayName,FX_BOOL bAbbr) const165 void CFX_Locale::GetDayName(int32_t nWeek,
166                             CFX_WideString& wsDayName,
167                             FX_BOOL bAbbr) const {
168   if (!m_pElement) {
169     return;
170   }
171   FX_GetCalendarSymbol(m_pElement, "day", nWeek, bAbbr, wsDayName);
172 }
GetMeridiemName(CFX_WideString & wsMeridiemName,FX_BOOL bAM) const173 void CFX_Locale::GetMeridiemName(CFX_WideString& wsMeridiemName,
174                                  FX_BOOL bAM) const {
175   if (!m_pElement) {
176     return;
177   }
178   FX_GetCalendarSymbol(m_pElement, "meridiem", bAM ? 0 : 1, FALSE,
179                        wsMeridiemName);
180 }
FX_ParseTimeZone(const FX_WCHAR * pStr,int32_t iLen,FX_TIMEZONE & tz)181 static int32_t FX_ParseTimeZone(const FX_WCHAR* pStr,
182                                 int32_t iLen,
183                                 FX_TIMEZONE& tz) {
184   tz.tzHour = 0;
185   tz.tzMinute = 0;
186   if (iLen < 0) {
187     return 0;
188   }
189   int32_t iStart = 1;
190   int32_t iEnd = iStart + 2;
191   while (iStart < iLen && iStart < iEnd) {
192     tz.tzHour = tz.tzHour * 10 + pStr[iStart++] - '0';
193   }
194   if (iStart < iLen && pStr[iStart] == ':') {
195     iStart++;
196   }
197   iEnd = iStart + 2;
198   while (iStart < iLen && iStart < iEnd) {
199     tz.tzMinute = tz.tzMinute * 10 + pStr[iStart++] - '0';
200   }
201   if (pStr[0] == '-') {
202     tz.tzHour = -tz.tzHour;
203   }
204   return iStart;
205 }
GetTimeZone(FX_TIMEZONE & tz) const206 void CFX_Locale::GetTimeZone(FX_TIMEZONE& tz) const {
207   tz.tzHour = 0;
208   tz.tzMinute = 0;
209   if (!m_pElement) {
210     return;
211   }
212   CXML_Element* pxmlTimeZone = m_pElement->GetElement("", "timeZone");
213   if (pxmlTimeZone) {
214     CFX_WideString wsTimeZone = pxmlTimeZone->GetContent(0);
215     FX_ParseTimeZone(wsTimeZone, wsTimeZone.GetLength(), tz);
216   }
217 }
GetEraName(CFX_WideString & wsEraName,FX_BOOL bAD) const218 void CFX_Locale::GetEraName(CFX_WideString& wsEraName, FX_BOOL bAD) const {
219   if (!m_pElement) {
220     return;
221   }
222   FX_GetCalendarSymbol(m_pElement, "era", bAD ? 0 : 1, FALSE, wsEraName);
223 }
FX_GetPattern(CXML_Element * pXmlElement,const CFX_ByteString & bsCategory,const CFX_WideString & wsSubCategory,CFX_WideString & wsPattern)224 static void FX_GetPattern(CXML_Element* pXmlElement,
225                           const CFX_ByteString& bsCategory,
226                           const CFX_WideString& wsSubCategory,
227                           CFX_WideString& wsPattern) {
228   CFX_ByteString bsSpace;
229   CXML_Element* pDatePatterns =
230       pXmlElement->GetElement(bsSpace, bsCategory + "s");
231   if (!pDatePatterns) {
232     return;
233   }
234   wsPattern =
235       FX_GetXMLContent(bsSpace, pDatePatterns, bsCategory, wsSubCategory);
236 }
FX_GetDateTimePattern(CXML_Element * pXmlElement,const CFX_ByteString & bsCategory,FX_LOCALEDATETIMESUBCATEGORY eType,CFX_WideString & wsPattern)237 static void FX_GetDateTimePattern(CXML_Element* pXmlElement,
238                                   const CFX_ByteString& bsCategory,
239                                   FX_LOCALEDATETIMESUBCATEGORY eType,
240                                   CFX_WideString& wsPattern) {
241   CFX_WideString wsType = g_FXLocaleDateTimeSubCatData[eType].pName;
242   FX_GetPattern(pXmlElement, bsCategory, wsType, wsPattern);
243 }
GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY eType,CFX_WideString & wsPattern) const244 void CFX_Locale::GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY eType,
245                                 CFX_WideString& wsPattern) const {
246   if (!m_pElement) {
247     return;
248   }
249   FX_GetDateTimePattern(m_pElement, "datePattern", eType, wsPattern);
250 }
GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY eType,CFX_WideString & wsPattern) const251 void CFX_Locale::GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY eType,
252                                 CFX_WideString& wsPattern) const {
253   if (!m_pElement) {
254     return;
255   }
256   FX_GetDateTimePattern(m_pElement, "timePattern", eType, wsPattern);
257 }
GetNumPattern(FX_LOCALENUMSUBCATEGORY eType,CFX_WideString & wsPattern) const258 void CFX_Locale::GetNumPattern(FX_LOCALENUMSUBCATEGORY eType,
259                                CFX_WideString& wsPattern) const {
260   CFX_WideString wsType = g_FXLocaleNumSubCatData[eType].pName;
261   FX_GetPattern(m_pElement, "numberPattern", wsType, wsPattern);
262 }
FX_IsDigit(FX_WCHAR c)263 static FX_BOOL FX_IsDigit(FX_WCHAR c) {
264   return c >= '0' && c <= '9';
265 }
FX_IsAlpha(FX_WCHAR c)266 static FX_BOOL FX_IsAlpha(FX_WCHAR c) {
267   return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
268 }
FX_IsSpace(FX_WCHAR c)269 static FX_BOOL FX_IsSpace(FX_WCHAR c) {
270   return (c == 0x20) || (c == 0x0d) || (c == 0x0a) || (c == 0x09);
271 }
272 static const FX_FLOAT gs_fraction_scales[] = {
273     0.1f,         0.01f,         0.001f,        0.0001f,
274     0.00001f,     0.000001f,     0.0000001f,    0.00000001f,
275     0.000000001f, 0.0000000001f, 0.00000000001f};
276 static const int32_t gs_fraction_count =
277     sizeof(gs_fraction_scales) / sizeof(FX_FLOAT);
278 class CFX_LCNumeric {
279  public:
280   CFX_LCNumeric();
281   CFX_LCNumeric(int64_t integral,
282                 FX_DWORD fractional = 0,
283                 int32_t exponent = 0);
284   CFX_LCNumeric(FX_FLOAT dbRetValue);
285   CFX_LCNumeric(double dbvalue);
286   CFX_LCNumeric(CFX_WideString& wsNumeric);
287 
288   FX_FLOAT GetFloat() const;
289   double GetDouble() const;
290   CFX_WideString ToString() const;
291   CFX_WideString ToString(int32_t nTreading, FX_BOOL bTrimTailZeros) const;
292   int64_t m_Integral;
293   FX_DWORD m_Fractional;
294 #ifdef FX_NUM_DOUBLE
295   CFX_WideString m_wsValue;
296 #endif
297   int32_t m_Exponent;
298 };
FX_WStringToNumeric(const CFX_WideString & wsValue,CFX_LCNumeric & lcnum)299 static FX_BOOL FX_WStringToNumeric(const CFX_WideString& wsValue,
300                                    CFX_LCNumeric& lcnum) {
301   int64_t* pIntegral = &lcnum.m_Integral;
302   FX_DWORD* pFractional = &lcnum.m_Fractional;
303   int32_t* pExponent = &lcnum.m_Exponent;
304   *pIntegral = 0;
305   *pFractional = 0;
306   *pExponent = 0;
307 #ifdef FX_NUM_DOUBLE
308   lcnum.m_wsValue.Empty();
309 #endif
310   if (wsValue.IsEmpty()) {
311     return FALSE;
312   }
313   const int32_t nIntegralMaxLen = 17;
314   int32_t cc = 0;
315   FX_BOOL bNegative = FALSE, bExpSign = FALSE;
316   const FX_WCHAR* str = (const FX_WCHAR*)wsValue;
317   int32_t len = wsValue.GetLength();
318   while (cc < len && FX_IsSpace(str[cc])) {
319     cc++;
320   }
321   if (cc >= len) {
322     return FALSE;
323   }
324   if (str[cc] == '+') {
325     cc++;
326   } else if (str[cc] == '-') {
327     bNegative = TRUE;
328     cc++;
329   }
330   int32_t nIntegralLen = 0;
331   while (cc < len) {
332     if (str[cc] == '.') {
333       break;
334     }
335     if (!FX_IsDigit(str[cc])) {
336       if ((str[cc] == 'E' || str[cc] == 'e')) {
337         break;
338       } else {
339         return FALSE;
340       }
341     }
342     if (nIntegralLen < nIntegralMaxLen) {
343       *pIntegral = *pIntegral * 10 + str[cc] - '0';
344       nIntegralLen++;
345     }
346     cc++;
347   }
348   *pIntegral = bNegative ? -*pIntegral : *pIntegral;
349   if (cc < len && str[cc] == '.') {
350     int scale = 0;
351     double fraction = 0.0;
352     cc++;
353     while (cc < len) {
354       if (scale >= gs_fraction_count) {
355         while (cc < len) {
356           if (!FX_IsDigit(str[cc])) {
357             break;
358           }
359           cc++;
360         }
361       }
362       if (!FX_IsDigit(str[cc])) {
363         if ((str[cc] == 'E' || str[cc] == 'e')) {
364           break;
365         } else {
366           return FALSE;
367         }
368       }
369       fraction += gs_fraction_scales[scale] * (str[cc] - '0');
370       scale++;
371       cc++;
372     }
373     *pFractional = (FX_DWORD)(fraction * 4294967296.0);
374   }
375   if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) {
376     cc++;
377     if (cc < len) {
378       if (str[cc] == '+') {
379         cc++;
380       } else if (str[cc] == '-') {
381         bExpSign = TRUE;
382         cc++;
383       }
384     }
385     while (cc < len) {
386       if (FX_IsDigit(str[cc])) {
387         return FALSE;
388       }
389       *pExponent = *pExponent * 10 + str[cc] - '0';
390       cc++;
391     }
392     *pExponent = bExpSign ? -*pExponent : *pExponent;
393   }
394 #ifdef FX_NUM_DOUBLE
395   else {
396     lcnum.m_wsValue = wsValue;
397   }
398 #endif
399   return TRUE;
400 }
CFX_LCNumeric()401 CFX_LCNumeric::CFX_LCNumeric() {
402   m_Integral = 0;
403   m_Fractional = 0;
404   m_Exponent = 0;
405 }
CFX_LCNumeric(int64_t integral,FX_DWORD fractional,int32_t exponent)406 CFX_LCNumeric::CFX_LCNumeric(int64_t integral,
407                              FX_DWORD fractional,
408                              int32_t exponent) {
409   m_Integral = integral;
410   m_Fractional = fractional;
411   m_Exponent = exponent;
412 }
CFX_LCNumeric(FX_FLOAT dbRetValue)413 CFX_LCNumeric::CFX_LCNumeric(FX_FLOAT dbRetValue) {
414   m_Integral = (int64_t)dbRetValue;
415   m_Fractional = (FX_DWORD)(((dbRetValue > 0) ? (dbRetValue - m_Integral)
416                                               : (m_Integral - dbRetValue)) *
417                             4294967296);
418   m_Exponent = 0;
419 }
CFX_LCNumeric(double dbvalue)420 CFX_LCNumeric::CFX_LCNumeric(double dbvalue) {
421   m_Integral = (int64_t)dbvalue;
422   m_Fractional = (FX_DWORD)(
423       ((dbvalue > 0) ? (dbvalue - m_Integral) : (m_Integral - dbvalue)) *
424       4294967296);
425   m_Exponent = 0;
426 }
CFX_LCNumeric(CFX_WideString & wsNumeric)427 CFX_LCNumeric::CFX_LCNumeric(CFX_WideString& wsNumeric) {
428   FX_WStringToNumeric(wsNumeric, *this);
429 }
GetFloat() const430 FX_FLOAT CFX_LCNumeric::GetFloat() const {
431   FX_FLOAT dbRetValue = m_Fractional / 4294967296.0f;
432   dbRetValue = m_Integral + (m_Integral >= 0 ? dbRetValue : -dbRetValue);
433   if (m_Exponent != 0) {
434     dbRetValue *= FXSYS_pow(10, (FX_FLOAT)m_Exponent);
435   }
436   return dbRetValue;
437 }
GetDouble() const438 double CFX_LCNumeric::GetDouble() const {
439   double value = m_Fractional / 4294967296.0;
440   value = m_Integral + (m_Integral >= 0 ? value : -value);
441   if (m_Exponent != 0) {
442     value *= FXSYS_pow(10, (FX_FLOAT)m_Exponent);
443   }
444   return value;
445 }
ToString() const446 CFX_WideString CFX_LCNumeric::ToString() const {
447   return ToString(8, TRUE);
448 }
ToString(int32_t nTreading,FX_BOOL bTrimTailZeros) const449 CFX_WideString CFX_LCNumeric::ToString(int32_t nTreading,
450                                        FX_BOOL bTrimTailZeros) const {
451 #ifdef FX_NUM_DOUBLE
452   CFX_WideString wsResult;
453   if (!m_wsValue.IsEmpty()) {
454     const int32_t nIntegralMaxLen = 17;
455     int32_t cc = 0;
456     FX_BOOL bNegative = FALSE, bExpSign = FALSE;
457     const FX_WCHAR* str = (const FX_WCHAR*)m_wsValue;
458     int32_t len = m_wsValue.GetLength();
459     while (cc < len && FX_IsSpace(str[cc])) {
460       cc++;
461     }
462     if (cc >= len) {
463       return wsResult;
464     }
465     if (str[cc] == '+') {
466       cc++;
467     } else if (str[cc] == '-') {
468       bNegative = TRUE;
469       cc++;
470     }
471     int32_t nIntegralLen = 0;
472     while (cc < len) {
473       if (str[cc] == '.') {
474         break;
475       }
476       if (!FX_IsDigit(str[cc])) {
477         if ((str[cc] == 'E' || str[cc] == 'e')) {
478           break;
479         } else {
480           return wsResult;
481         }
482       }
483       if (nIntegralLen < nIntegralMaxLen) {
484         *pIntegral = *pIntegral * 10 + str[cc] - '0';
485         nIntegralLen++;
486       }
487       cc++;
488     }
489     *pIntegral = bNegative ? -*pIntegral : *pIntegral;
490     if (cc < len && str[cc] == '.') {
491       int scale = 0;
492       double fraction = 0.0;
493       cc++;
494       while (cc < len) {
495         if (scale >= gs_fraction_count) {
496           while (cc < len) {
497             if (!FX_IsDigit(str[cc])) {
498               break;
499             }
500             cc++;
501           }
502         }
503         if (!FX_IsDigit(str[cc])) {
504           if ((str[cc] == 'E' || str[cc] == 'e')) {
505             break;
506           } else {
507             return FALSE;
508           }
509         }
510         fraction += gs_fraction_scales[scale] * (str[cc] - '0');
511         scale++;
512         cc++;
513       }
514       *pFractional = (FX_DWORD)(fraction * 4294967296.0);
515     }
516   }
517   double dbValeu = GetDouble();
518   int64_t iInte = (int64_t)dbValeu;
519   wsResult.Format(L"%l", (int64_t)iInte);
520   if (m_Fractional) {
521     CFX_WideString wsFormat;
522     wsFormat.Format(L"%%.%dG", nTreading);
523     double dblMantissa = (dbValeu > 0) ? (dbValeu - iInte) : (iInte - dbValeu);
524     CFX_WideString wsFrac;
525     wsFrac.Format((const FX_WCHAR*)wsFormat, dblMantissa);
526     wsResult +=
527         CFX_WideStringC((const FX_WCHAR*)wsFrac + 1, wsFrac.GetLength() - 1);
528     if (bTrimTailZeros && nTreading > 0) {
529       wsResult.TrimRight(L"0");
530       wsResult.TrimRight(L".");
531     }
532   }
533 #endif
534   CFX_WideString wsFormat;
535   wsFormat.Format(L"%%.%df", nTreading);
536   CFX_WideString wsResult;
537   wsResult.Format(wsFormat.c_str(), GetDouble());
538   if (bTrimTailZeros && nTreading > 0) {
539     wsResult.TrimRight(L"0");
540     wsResult.TrimRight(L".");
541   }
542   return wsResult;
543 }
Create(IFX_LocaleMgr * pLocaleMgr,FX_BOOL bUseLCID)544 IFX_FormatString* IFX_FormatString::Create(IFX_LocaleMgr* pLocaleMgr,
545                                            FX_BOOL bUseLCID) {
546   if (!pLocaleMgr) {
547     return NULL;
548   }
549   return new CFX_FormatString(pLocaleMgr, bUseLCID);
550 }
CFX_FormatString(IFX_LocaleMgr * pLocaleMgr,FX_BOOL bUseLCID)551 CFX_FormatString::CFX_FormatString(IFX_LocaleMgr* pLocaleMgr, FX_BOOL bUseLCID)
552     : m_pLocaleMgr(pLocaleMgr), m_bUseLCID(bUseLCID) {}
~CFX_FormatString()553 CFX_FormatString::~CFX_FormatString() {}
SplitFormatString(const CFX_WideString & wsFormatString,CFX_WideStringArray & wsPatterns)554 void CFX_FormatString::SplitFormatString(const CFX_WideString& wsFormatString,
555                                          CFX_WideStringArray& wsPatterns) {
556   int32_t iStrLen = wsFormatString.GetLength();
557   const FX_WCHAR* pStr = (const FX_WCHAR*)wsFormatString;
558   const FX_WCHAR* pToken = pStr;
559   const FX_WCHAR* pEnd = pStr + iStrLen;
560   FX_BOOL iQuote = FALSE;
561   while (TRUE) {
562     if (pStr >= pEnd) {
563       CFX_WideString sub(pToken, pStr - pToken);
564       wsPatterns.Add(sub);
565       return;
566     } else if (*pStr == '\'') {
567       iQuote = !iQuote;
568     } else if (*pStr == L'|' && !iQuote) {
569       CFX_WideString sub(pToken, pStr - pToken);
570       wsPatterns.Add(sub);
571       pToken = pStr + 1;
572     }
573     pStr++;
574   }
575 }
FX_GetLiteralText(const FX_WCHAR * pStrPattern,int32_t & iPattern,int32_t iLenPattern)576 static CFX_WideString FX_GetLiteralText(const FX_WCHAR* pStrPattern,
577                                         int32_t& iPattern,
578                                         int32_t iLenPattern) {
579   CFX_WideString wsOutput;
580   if (pStrPattern[iPattern] != '\'') {
581     return wsOutput;
582   }
583   iPattern++;
584   int32_t iQuote = 1;
585   while (iPattern < iLenPattern) {
586     if (pStrPattern[iPattern] == '\'') {
587       iQuote++;
588       if ((iPattern + 1 >= iLenPattern) ||
589           ((pStrPattern[iPattern + 1] != '\'') && (iQuote % 2 == 0))) {
590         break;
591       } else {
592         iQuote++;
593       }
594       iPattern++;
595     } else if (pStrPattern[iPattern] == '\\' && (iPattern + 1 < iLenPattern) &&
596                pStrPattern[iPattern + 1] == 'u') {
597       int32_t iKeyValue = 0;
598       iPattern += 2;
599       int32_t i = 0;
600       while (iPattern < iLenPattern && i++ < 4) {
601         FX_WCHAR ch = pStrPattern[iPattern++];
602         if ((ch >= '0' && ch <= '9')) {
603           iKeyValue = iKeyValue * 16 + ch - '0';
604         } else if ((ch >= 'a' && ch <= 'f')) {
605           iKeyValue = iKeyValue * 16 + ch - 'a' + 10;
606         } else if ((ch >= 'A' && ch <= 'F')) {
607           iKeyValue = iKeyValue * 16 + ch - 'A' + 10;
608         }
609       }
610       if (iKeyValue != 0) {
611         wsOutput += (FX_WCHAR)(iKeyValue & 0x0000FFFF);
612       }
613       continue;
614     }
615     wsOutput += pStrPattern[iPattern++];
616   }
617   return wsOutput;
618 }
FX_GetLiteralTextReverse(const FX_WCHAR * pStrPattern,int32_t & iPattern)619 static CFX_WideString FX_GetLiteralTextReverse(const FX_WCHAR* pStrPattern,
620                                                int32_t& iPattern) {
621   CFX_WideString wsOutput;
622   if (pStrPattern[iPattern] != '\'') {
623     return wsOutput;
624   }
625   iPattern--;
626   int32_t iQuote = 1;
627   while (iPattern >= 0) {
628     if (pStrPattern[iPattern] == '\'') {
629       iQuote++;
630       if (iPattern - 1 >= 0 ||
631           ((pStrPattern[iPattern - 1] != '\'') && (iQuote % 2 == 0))) {
632         break;
633       } else {
634         iQuote++;
635       }
636       iPattern--;
637     } else if (pStrPattern[iPattern] == '\\' &&
638                pStrPattern[iPattern + 1] == 'u') {
639       iPattern--;
640       int32_t iKeyValue = 0;
641       int32_t iLen = wsOutput.GetLength();
642       int32_t i = 1;
643       for (; i < iLen && i < 5; i++) {
644         FX_WCHAR ch = wsOutput[i];
645         if ((ch >= '0' && ch <= '9')) {
646           iKeyValue = iKeyValue * 16 + ch - '0';
647         } else if ((ch >= 'a' && ch <= 'f')) {
648           iKeyValue = iKeyValue * 16 + ch - 'a' + 10;
649         } else if ((ch >= 'A' && ch <= 'F')) {
650           iKeyValue = iKeyValue * 16 + ch - 'A' + 10;
651         }
652       }
653       if (iKeyValue != 0) {
654         wsOutput.Delete(0, i);
655         wsOutput = (FX_WCHAR)(iKeyValue & 0x0000FFFF) + wsOutput;
656       }
657       continue;
658     }
659     wsOutput = pStrPattern[iPattern--] + wsOutput;
660   }
661   return wsOutput;
662 }
GetCategory(const CFX_WideString & wsPattern)663 FX_LOCALECATEGORY CFX_FormatString::GetCategory(
664     const CFX_WideString& wsPattern) {
665   FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown;
666   int32_t ccf = 0;
667   int32_t iLenf = wsPattern.GetLength();
668   const FX_WCHAR* pStr = (const FX_WCHAR*)wsPattern;
669   FX_BOOL bBraceOpen = FALSE;
670   while (ccf < iLenf) {
671     if (pStr[ccf] == '\'') {
672       FX_GetLiteralText(pStr, ccf, iLenf);
673     } else if (!bBraceOpen && FX_Local_Find(gs_wsConstChars, pStr[ccf]) < 0) {
674       CFX_WideString wsCategory(pStr[ccf]);
675       ccf++;
676       while (TRUE) {
677         if (ccf == iLenf) {
678           return eCategory;
679         }
680         if (pStr[ccf] == '.' || pStr[ccf] == '(') {
681           break;
682         }
683         if (pStr[ccf] == '{') {
684           bBraceOpen = TRUE;
685           break;
686         }
687         wsCategory += pStr[ccf];
688         ccf++;
689       }
690       FX_DWORD dwHash =
691           FX_HashCode_String_GetW(wsCategory, wsCategory.GetLength());
692       if (dwHash == FX_LOCALECATEGORY_DateHash) {
693         if (eCategory == FX_LOCALECATEGORY_Time) {
694           return FX_LOCALECATEGORY_DateTime;
695         }
696         eCategory = FX_LOCALECATEGORY_Date;
697       } else if (dwHash == FX_LOCALECATEGORY_TimeHash) {
698         if (eCategory == FX_LOCALECATEGORY_Date) {
699           return FX_LOCALECATEGORY_DateTime;
700         }
701         eCategory = FX_LOCALECATEGORY_Time;
702       } else if (dwHash == FX_LOCALECATEGORY_DateTimeHash) {
703         return FX_LOCALECATEGORY_DateTime;
704       } else if (dwHash == FX_LOCALECATEGORY_TextHash) {
705         return FX_LOCALECATEGORY_Text;
706       } else if (dwHash == FX_LOCALECATEGORY_NumHash) {
707         return FX_LOCALECATEGORY_Num;
708       } else if (dwHash == FX_LOCALECATEGORY_ZeroHash) {
709         return FX_LOCALECATEGORY_Zero;
710       } else if (dwHash == FX_LOCALECATEGORY_NullHash) {
711         return FX_LOCALECATEGORY_Null;
712       }
713     } else if (pStr[ccf] == '}') {
714       bBraceOpen = FALSE;
715     }
716     ccf++;
717   }
718   return eCategory;
719 }
FX_WStringToLCID(const FX_WCHAR * pstrLCID)720 static FX_WORD FX_WStringToLCID(const FX_WCHAR* pstrLCID) {
721   if (!pstrLCID) {
722     return 0;
723   }
724   wchar_t* pEnd;
725   return (FX_WORD)wcstol((wchar_t*)pstrLCID, &pEnd, 16);
726 }
GetLCID(const CFX_WideString & wsPattern)727 FX_WORD CFX_FormatString::GetLCID(const CFX_WideString& wsPattern) {
728   return FX_WStringToLCID(GetLocaleName(wsPattern));
729 }
GetLocaleName(const CFX_WideString & wsPattern)730 CFX_WideString CFX_FormatString::GetLocaleName(
731     const CFX_WideString& wsPattern) {
732   int32_t ccf = 0;
733   int32_t iLenf = wsPattern.GetLength();
734   const FX_WCHAR* pStr = (const FX_WCHAR*)wsPattern;
735   while (ccf < iLenf) {
736     if (pStr[ccf] == '\'') {
737       FX_GetLiteralText(pStr, ccf, iLenf);
738     } else if (pStr[ccf] == '(') {
739       ccf++;
740       CFX_WideString wsLCID;
741       while (ccf < iLenf && pStr[ccf] != ')') {
742         wsLCID += pStr[ccf++];
743       }
744       return wsLCID;
745     }
746     ccf++;
747   }
748   return CFX_WideString();
749 }
GetTextFormat(const CFX_WideString & wsPattern,const CFX_WideStringC & wsCategory,CFX_WideString & wsPurgePattern)750 IFX_Locale* CFX_FormatString::GetTextFormat(const CFX_WideString& wsPattern,
751                                             const CFX_WideStringC& wsCategory,
752                                             CFX_WideString& wsPurgePattern) {
753   IFX_Locale* pLocale = NULL;
754   int32_t ccf = 0;
755   int32_t iLenf = wsPattern.GetLength();
756   const FX_WCHAR* pStr = (const FX_WCHAR*)wsPattern;
757   FX_BOOL bBrackOpen = FALSE;
758   while (ccf < iLenf) {
759     if (pStr[ccf] == '\'') {
760       int32_t iCurChar = ccf;
761       FX_GetLiteralText(pStr, ccf, iLenf);
762       wsPurgePattern += CFX_WideStringC(pStr + iCurChar, ccf - iCurChar + 1);
763     } else if (!bBrackOpen && FX_Local_Find(gs_wsConstChars, pStr[ccf]) < 0) {
764       CFX_WideString wsSearchCategory(pStr[ccf]);
765       ccf++;
766       while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' &&
767              pStr[ccf] != '(') {
768         wsSearchCategory += pStr[ccf];
769         ccf++;
770       }
771       if (wsSearchCategory != wsCategory) {
772         continue;
773       }
774       while (ccf < iLenf) {
775         if (pStr[ccf] == '(') {
776           ccf++;
777           CFX_WideString wsLCID;
778           while (ccf < iLenf && pStr[ccf] != ')') {
779             wsLCID += pStr[ccf++];
780           }
781           pLocale = GetPatternLocale(wsLCID);
782         } else if (pStr[ccf] == '{') {
783           bBrackOpen = TRUE;
784           break;
785         }
786         ccf++;
787       }
788     } else if (pStr[ccf] != '}') {
789       wsPurgePattern += pStr[ccf];
790     }
791     ccf++;
792   }
793   if (!bBrackOpen) {
794     wsPurgePattern = wsPattern;
795   }
796   if (!pLocale) {
797     pLocale = m_pLocaleMgr->GetDefLocale();
798   }
799   return pLocale;
800 }
801 #define FX_NUMSTYLE_Percent 0x01
802 #define FX_NUMSTYLE_Exponent 0x02
803 #define FX_NUMSTYLE_DotVorv 0x04
GetNumericFormat(const CFX_WideString & wsPattern,int32_t & iDotIndex,FX_DWORD & dwStyle,CFX_WideString & wsPurgePattern)804 IFX_Locale* CFX_FormatString::GetNumericFormat(const CFX_WideString& wsPattern,
805                                                int32_t& iDotIndex,
806                                                FX_DWORD& dwStyle,
807                                                CFX_WideString& wsPurgePattern) {
808   dwStyle = 0;
809   IFX_Locale* pLocale = NULL;
810   int32_t ccf = 0;
811   int32_t iLenf = wsPattern.GetLength();
812   const FX_WCHAR* pStr = (const FX_WCHAR*)wsPattern;
813   FX_BOOL bFindDot = FALSE;
814   FX_BOOL bBrackOpen = FALSE;
815   while (ccf < iLenf) {
816     if (pStr[ccf] == '\'') {
817       int32_t iCurChar = ccf;
818       FX_GetLiteralText(pStr, ccf, iLenf);
819       wsPurgePattern += CFX_WideStringC(pStr + iCurChar, ccf - iCurChar + 1);
820     } else if (!bBrackOpen && FX_Local_Find(gs_wsConstChars, pStr[ccf]) < 0) {
821       CFX_WideString wsCategory(pStr[ccf]);
822       ccf++;
823       while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' &&
824              pStr[ccf] != '(') {
825         wsCategory += pStr[ccf];
826         ccf++;
827       }
828       if (wsCategory != FX_WSTRC(L"num")) {
829         bBrackOpen = TRUE;
830         ccf = 0;
831         continue;
832       }
833       while (ccf < iLenf) {
834         if (pStr[ccf] == '(') {
835           ccf++;
836           CFX_WideString wsLCID;
837           while (ccf < iLenf && pStr[ccf] != ')') {
838             wsLCID += pStr[ccf++];
839           }
840           pLocale = GetPatternLocale(wsLCID);
841         } else if (pStr[ccf] == '{') {
842           bBrackOpen = TRUE;
843           break;
844         } else if (pStr[ccf] == '.') {
845           CFX_WideString wsSubCategory;
846           ccf++;
847           while (ccf < iLenf && pStr[ccf] != '(' && pStr[ccf] != '{') {
848             wsSubCategory += pStr[ccf++];
849           }
850           FX_DWORD dwSubHash =
851               FX_HashCode_String_GetW(wsSubCategory, wsSubCategory.GetLength());
852           FX_LOCALENUMSUBCATEGORY eSubCategory = FX_LOCALENUMPATTERN_Decimal;
853           for (int32_t i = 0; i < g_iFXLocaleNumSubCatCount; i++) {
854             if (g_FXLocaleNumSubCatData[i].uHash == dwSubHash) {
855               eSubCategory = (FX_LOCALENUMSUBCATEGORY)g_FXLocaleNumSubCatData[i]
856                                  .eSubCategory;
857               break;
858             }
859           }
860           wsSubCategory.Empty();
861           if (!pLocale) {
862             pLocale = m_pLocaleMgr->GetDefLocale();
863           }
864           FXSYS_assert(pLocale != NULL);
865           pLocale->GetNumPattern(eSubCategory, wsSubCategory);
866           iDotIndex = wsSubCategory.Find('.');
867           if (iDotIndex > 0) {
868             iDotIndex += wsPurgePattern.GetLength();
869             bFindDot = TRUE;
870             dwStyle |= FX_NUMSTYLE_DotVorv;
871           }
872           wsPurgePattern += wsSubCategory;
873           if (eSubCategory == FX_LOCALENUMPATTERN_Percent) {
874             dwStyle |= FX_NUMSTYLE_Percent;
875           }
876           continue;
877         }
878         ccf++;
879       }
880     } else if (pStr[ccf] == 'E') {
881       dwStyle |= FX_NUMSTYLE_Exponent;
882       wsPurgePattern += pStr[ccf];
883     } else if (pStr[ccf] == '%') {
884       dwStyle |= FX_NUMSTYLE_Percent;
885       wsPurgePattern += pStr[ccf];
886     } else if (pStr[ccf] != '}') {
887       wsPurgePattern += pStr[ccf];
888     }
889     if (!bFindDot) {
890       if (pStr[ccf] == '.' || pStr[ccf] == 'V' || pStr[ccf] == 'v') {
891         bFindDot = TRUE;
892         iDotIndex = wsPurgePattern.GetLength() - 1;
893         dwStyle |= FX_NUMSTYLE_DotVorv;
894       }
895     }
896     ccf++;
897   }
898   if (!bFindDot) {
899     iDotIndex = wsPurgePattern.GetLength();
900   }
901   if (!pLocale) {
902     pLocale = m_pLocaleMgr->GetDefLocale();
903   }
904   return pLocale;
905 }
FX_GetNumericDotIndex(const CFX_WideString & wsNum,const CFX_WideString & wsDotSymbol,int32_t & iDotIndex)906 static FX_BOOL FX_GetNumericDotIndex(const CFX_WideString& wsNum,
907                                      const CFX_WideString& wsDotSymbol,
908                                      int32_t& iDotIndex) {
909   int32_t ccf = 0;
910   int32_t iLenf = wsNum.GetLength();
911   const FX_WCHAR* pStr = (const FX_WCHAR*)wsNum;
912   int32_t iLenDot = wsDotSymbol.GetLength();
913   while (ccf < iLenf) {
914     if (pStr[ccf] == '\'') {
915       FX_GetLiteralText(pStr, ccf, iLenf);
916     } else if (ccf + iLenDot <= iLenf &&
917                !FXSYS_wcsncmp(pStr + ccf, (const FX_WCHAR*)wsDotSymbol,
918                               iLenDot)) {
919       iDotIndex = ccf;
920       return TRUE;
921     }
922     ccf++;
923   }
924   iDotIndex = wsNum.Find('.');
925   if (iDotIndex < 0) {
926     iDotIndex = iLenf;
927     return FALSE;
928   }
929   return TRUE;
930 }
ParseText(const CFX_WideString & wsSrcText,const CFX_WideString & wsPattern,CFX_WideString & wsValue)931 FX_BOOL CFX_FormatString::ParseText(const CFX_WideString& wsSrcText,
932                                     const CFX_WideString& wsPattern,
933                                     CFX_WideString& wsValue) {
934   wsValue.Empty();
935   if (wsSrcText.IsEmpty() || wsPattern.IsEmpty()) {
936     return FALSE;
937   }
938   CFX_WideString wsTextFormat;
939   GetTextFormat(wsPattern, FX_WSTRC(L"text"), wsTextFormat);
940   if (wsTextFormat.IsEmpty()) {
941     return FALSE;
942   }
943   int32_t iText = 0, iPattern = 0;
944   const FX_WCHAR* pStrText = (const FX_WCHAR*)wsSrcText;
945   int32_t iLenText = wsSrcText.GetLength();
946   const FX_WCHAR* pStrPattern = (const FX_WCHAR*)wsTextFormat;
947   int32_t iLenPattern = wsTextFormat.GetLength();
948   while (iPattern < iLenPattern && iText < iLenText) {
949     switch (pStrPattern[iPattern]) {
950       case '\'': {
951         CFX_WideString wsLiteral =
952             FX_GetLiteralText(pStrPattern, iPattern, iLenPattern);
953         int32_t iLiteralLen = wsLiteral.GetLength();
954         if (iText + iLiteralLen > iLenText ||
955             FXSYS_wcsncmp(pStrText + iText, (const FX_WCHAR*)wsLiteral,
956                           iLiteralLen)) {
957           wsValue = wsSrcText;
958           return FALSE;
959         }
960         iText += iLiteralLen;
961         iPattern++;
962         break;
963       }
964       case 'A':
965         if (FX_IsAlpha(pStrText[iText])) {
966           wsValue += pStrText[iText];
967           iText++;
968         }
969         iPattern++;
970         break;
971       case 'X':
972         wsValue += pStrText[iText];
973         iText++;
974         iPattern++;
975         break;
976       case 'O':
977       case '0':
978         if (FX_IsDigit(pStrText[iText]) || FX_IsAlpha(pStrText[iText])) {
979           wsValue += pStrText[iText];
980           iText++;
981         }
982         iPattern++;
983         break;
984       case '9':
985         if (FX_IsDigit(pStrText[iText])) {
986           wsValue += pStrText[iText];
987           iText++;
988         }
989         iPattern++;
990         break;
991       default:
992         if (pStrPattern[iPattern] != pStrText[iText]) {
993           wsValue = wsSrcText;
994           return FALSE;
995         }
996         iPattern++;
997         iText++;
998         break;
999     }
1000   }
1001   return iPattern == iLenPattern && iText == iLenText;
1002 }
ParseNum(const CFX_WideString & wsSrcNum,const CFX_WideString & wsPattern,FX_FLOAT & fValue)1003 FX_BOOL CFX_FormatString::ParseNum(const CFX_WideString& wsSrcNum,
1004                                    const CFX_WideString& wsPattern,
1005                                    FX_FLOAT& fValue) {
1006   fValue = 0.0f;
1007   if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty()) {
1008     return FALSE;
1009   }
1010   int32_t dot_index_f = -1;
1011   FX_DWORD dwFormatStyle = 0;
1012   CFX_WideString wsNumFormat;
1013   IFX_Locale* pLocale =
1014       GetNumericFormat(wsPattern, dot_index_f, dwFormatStyle, wsNumFormat);
1015   if (!pLocale || wsNumFormat.IsEmpty()) {
1016     return FALSE;
1017   }
1018   int32_t iExponent = 0;
1019   CFX_WideString wsDotSymbol;
1020   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsDotSymbol);
1021   CFX_WideString wsGroupSymbol;
1022   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping, wsGroupSymbol);
1023   int32_t iGroupLen = wsGroupSymbol.GetLength();
1024   CFX_WideString wsMinus;
1025   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinus);
1026   int32_t iMinusLen = wsMinus.GetLength();
1027   int cc = 0, ccf = 0;
1028   const FX_WCHAR* str = (const FX_WCHAR*)wsSrcNum;
1029   int len = wsSrcNum.GetLength();
1030   const FX_WCHAR* strf = (const FX_WCHAR*)wsNumFormat;
1031   int lenf = wsNumFormat.GetLength();
1032   double dbRetValue = 0;
1033   double coeff = 1;
1034   FX_BOOL bHavePercentSymbol = FALSE;
1035   FX_BOOL bNeg = FALSE;
1036   FX_BOOL bReverseParse = FALSE;
1037   int32_t dot_index = 0;
1038   if (!FX_GetNumericDotIndex(wsSrcNum, wsDotSymbol, dot_index) &&
1039       (dwFormatStyle & FX_NUMSTYLE_DotVorv)) {
1040     bReverseParse = TRUE;
1041   }
1042   bReverseParse = FALSE;
1043   if (bReverseParse) {
1044     ccf = lenf - 1;
1045     cc = len - 1;
1046     while (ccf > dot_index_f && cc >= 0) {
1047       switch (strf[ccf]) {
1048         case '\'': {
1049           CFX_WideString wsLiteral = FX_GetLiteralTextReverse(strf, ccf);
1050           int32_t iLiteralLen = wsLiteral.GetLength();
1051           cc -= iLiteralLen - 1;
1052           if (cc < 0 || FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsLiteral,
1053                                       iLiteralLen)) {
1054             return FALSE;
1055           }
1056           cc--;
1057           ccf--;
1058           break;
1059         }
1060         case '9':
1061           if (!FX_IsDigit(str[cc])) {
1062             return FALSE;
1063           }
1064           dbRetValue = dbRetValue * coeff + (str[cc] - '0') * 0.1;
1065           coeff *= 0.1;
1066           cc--;
1067           ccf--;
1068           break;
1069         case 'z':
1070           if (cc >= 0) {
1071             dbRetValue = dbRetValue * coeff + (str[cc] - '0') * 0.1;
1072             coeff *= 0.1;
1073             cc--;
1074           }
1075           ccf--;
1076           break;
1077         case 'Z':
1078           if (str[cc] != ' ') {
1079             dbRetValue = dbRetValue * coeff + (str[cc] - '0') * 0.1;
1080             coeff *= 0.1;
1081           }
1082           cc--;
1083           ccf--;
1084           break;
1085         case 'S':
1086           if (str[cc] == '+' || str[cc] == ' ') {
1087             cc--;
1088           } else {
1089             cc -= iMinusLen - 1;
1090             if (cc < 0 ||
1091                 FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
1092               return FALSE;
1093             }
1094             cc--;
1095             bNeg = TRUE;
1096           }
1097           ccf--;
1098           break;
1099         case 's':
1100           if (str[cc] == '+') {
1101             cc--;
1102           } else {
1103             cc -= iMinusLen - 1;
1104             if (cc < 0 ||
1105                 FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
1106               return FALSE;
1107             }
1108             cc--;
1109             bNeg = TRUE;
1110           }
1111           ccf--;
1112           break;
1113         case 'E': {
1114           if (cc >= dot_index) {
1115             return FALSE;
1116           }
1117           FX_BOOL bExpSign = FALSE;
1118           while (cc >= 0) {
1119             if (str[cc] == 'E' || str[cc] == 'e') {
1120               break;
1121             }
1122             if (FX_IsDigit(str[cc])) {
1123               iExponent = iExponent + (str[cc] - '0') * 10;
1124               cc--;
1125               continue;
1126             } else if (str[cc] == '+') {
1127               cc--;
1128               continue;
1129             } else if (cc - iMinusLen + 1 > 0 &&
1130                        !FXSYS_wcsncmp(str + (cc - iMinusLen + 1),
1131                                       (const FX_WCHAR*)wsMinus, iMinusLen)) {
1132               bExpSign = TRUE;
1133               cc -= iMinusLen;
1134             } else {
1135               return FALSE;
1136             }
1137           }
1138           cc--;
1139           iExponent = bExpSign ? -iExponent : iExponent;
1140           ccf--;
1141         } break;
1142         case '$': {
1143           CFX_WideString wsSymbol;
1144           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol,
1145                                      wsSymbol);
1146           int32_t iSymbolLen = wsSymbol.GetLength();
1147           cc -= iSymbolLen - 1;
1148           if (cc < 0 ||
1149               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol, iSymbolLen)) {
1150             return FALSE;
1151           }
1152           cc--;
1153           ccf--;
1154         } break;
1155         case 'r':
1156           if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {
1157             if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {
1158               bNeg = TRUE;
1159               cc -= 2;
1160             }
1161             ccf -= 2;
1162           } else {
1163             ccf--;
1164           }
1165           break;
1166         case 'R':
1167           if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {
1168             if (str[cc] == ' ') {
1169               cc++;
1170             } else if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {
1171               bNeg = TRUE;
1172               cc -= 2;
1173             }
1174             ccf -= 2;
1175           } else {
1176             ccf--;
1177           }
1178           break;
1179         case 'b':
1180           if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {
1181             if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {
1182               bNeg = TRUE;
1183               cc -= 2;
1184             }
1185             ccf -= 2;
1186           } else {
1187             ccf--;
1188           }
1189           break;
1190         case 'B':
1191           if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {
1192             if (str[cc] == ' ') {
1193               cc++;
1194             } else if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {
1195               bNeg = TRUE;
1196               cc -= 2;
1197             }
1198             ccf -= 2;
1199           } else {
1200             ccf--;
1201           }
1202           break;
1203         case '.':
1204         case 'V':
1205         case 'v':
1206           return FALSE;
1207         case '%': {
1208           CFX_WideString wsSymbol;
1209           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
1210           int32_t iSysmbolLen = wsSymbol.GetLength();
1211           cc -= iSysmbolLen - 1;
1212           if (cc < 0 ||
1213               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol, iSysmbolLen)) {
1214             return FALSE;
1215           }
1216           cc--;
1217           ccf--;
1218           bHavePercentSymbol = TRUE;
1219         } break;
1220         case '8':
1221           while (ccf < lenf && strf[ccf] == '8') {
1222             ccf++;
1223           }
1224           while (cc < len && FX_IsDigit(str[cc])) {
1225             dbRetValue = (str[cc] - '0') * coeff + dbRetValue;
1226             coeff *= 0.1;
1227             cc++;
1228           }
1229           break;
1230         case ',': {
1231           if (cc >= 0) {
1232             cc -= iGroupLen - 1;
1233             if (cc >= 0 &&
1234                 FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsGroupSymbol,
1235                               iGroupLen) == 0) {
1236               cc--;
1237             } else {
1238               cc += iGroupLen - 1;
1239             }
1240           }
1241           ccf--;
1242         } break;
1243         case '(':
1244           if (str[cc] == L'(') {
1245             bNeg = TRUE;
1246           } else if (str[cc] != L' ') {
1247             return FALSE;
1248           }
1249           cc--;
1250           ccf--;
1251           break;
1252         case ')':
1253           if (str[cc] == L')') {
1254             bNeg = TRUE;
1255           } else if (str[cc] != L' ') {
1256             return FALSE;
1257           }
1258           cc--;
1259           ccf--;
1260           break;
1261         default:
1262           if (strf[ccf] != str[cc]) {
1263             return FALSE;
1264           }
1265           cc--;
1266           ccf--;
1267       }
1268     }
1269     dot_index = cc + 1;
1270   }
1271   ccf = dot_index_f - 1;
1272   cc = dot_index - 1;
1273   coeff = 1;
1274   while (ccf >= 0 && cc >= 0) {
1275     switch (strf[ccf]) {
1276       case '\'': {
1277         CFX_WideString wsLiteral = FX_GetLiteralTextReverse(strf, ccf);
1278         int32_t iLiteralLen = wsLiteral.GetLength();
1279         cc -= iLiteralLen - 1;
1280         if (cc < 0 ||
1281             FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsLiteral, iLiteralLen)) {
1282           return FALSE;
1283         }
1284         cc--;
1285         ccf--;
1286         break;
1287       }
1288       case '9':
1289         if (!FX_IsDigit(str[cc])) {
1290           return FALSE;
1291         }
1292         dbRetValue = dbRetValue + (str[cc] - '0') * coeff;
1293         coeff *= 10;
1294         cc--;
1295         ccf--;
1296         break;
1297       case 'z':
1298         if (FX_IsDigit(str[cc])) {
1299           dbRetValue = dbRetValue + (str[cc] - '0') * coeff;
1300           coeff *= 10;
1301           cc--;
1302         }
1303         ccf--;
1304         break;
1305       case 'Z':
1306         if (str[cc] != ' ') {
1307           if (FX_IsDigit(str[cc])) {
1308             dbRetValue = dbRetValue + (str[cc] - '0') * coeff;
1309             coeff *= 10;
1310             cc--;
1311           }
1312         } else {
1313           cc--;
1314         }
1315         ccf--;
1316         break;
1317       case 'S':
1318         if (str[cc] == '+' || str[cc] == ' ') {
1319           cc--;
1320         } else {
1321           cc -= iMinusLen - 1;
1322           if (cc < 0 ||
1323               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
1324             return FALSE;
1325           }
1326           cc--;
1327           bNeg = TRUE;
1328         }
1329         ccf--;
1330         break;
1331       case 's':
1332         if (str[cc] == '+') {
1333           cc--;
1334         } else {
1335           cc -= iMinusLen - 1;
1336           if (cc < 0 ||
1337               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
1338             return FALSE;
1339           }
1340           cc--;
1341           bNeg = TRUE;
1342         }
1343         ccf--;
1344         break;
1345       case 'E': {
1346         if (cc >= dot_index) {
1347           return FALSE;
1348         }
1349         FX_BOOL bExpSign = FALSE;
1350         while (cc >= 0) {
1351           if (str[cc] == 'E' || str[cc] == 'e') {
1352             break;
1353           }
1354           if (FX_IsDigit(str[cc])) {
1355             iExponent = iExponent + (str[cc] - '0') * 10;
1356             cc--;
1357             continue;
1358           } else if (str[cc] == '+') {
1359             cc--;
1360             continue;
1361           } else if (cc - iMinusLen + 1 > 0 &&
1362                      !FXSYS_wcsncmp(str + (cc - iMinusLen + 1),
1363                                     (const FX_WCHAR*)wsMinus, iMinusLen)) {
1364             bExpSign = TRUE;
1365             cc -= iMinusLen;
1366           } else {
1367             return FALSE;
1368           }
1369         }
1370         cc--;
1371         iExponent = bExpSign ? -iExponent : iExponent;
1372         ccf--;
1373       } break;
1374       case '$': {
1375         CFX_WideString wsSymbol;
1376         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);
1377         int32_t iSymbolLen = wsSymbol.GetLength();
1378         cc -= iSymbolLen - 1;
1379         if (cc < 0 ||
1380             FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol, iSymbolLen)) {
1381           return FALSE;
1382         }
1383         cc--;
1384         ccf--;
1385       } break;
1386       case 'r':
1387         if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {
1388           if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {
1389             bNeg = TRUE;
1390             cc -= 2;
1391           }
1392           ccf -= 2;
1393         } else {
1394           ccf--;
1395         }
1396         break;
1397       case 'R':
1398         if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {
1399           if (str[cc] == ' ') {
1400             cc++;
1401           } else if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {
1402             bNeg = TRUE;
1403             cc -= 2;
1404           }
1405           ccf -= 2;
1406         } else {
1407           ccf--;
1408         }
1409         break;
1410       case 'b':
1411         if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {
1412           if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {
1413             bNeg = TRUE;
1414             cc -= 2;
1415           }
1416           ccf -= 2;
1417         } else {
1418           ccf--;
1419         }
1420         break;
1421       case 'B':
1422         if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {
1423           if (str[cc] == ' ') {
1424             cc++;
1425           } else if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {
1426             bNeg = TRUE;
1427             cc -= 2;
1428           }
1429           ccf -= 2;
1430         } else {
1431           ccf--;
1432         }
1433         break;
1434       case '.':
1435       case 'V':
1436       case 'v':
1437         return FALSE;
1438       case '%': {
1439         CFX_WideString wsSymbol;
1440         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
1441         int32_t iSysmbolLen = wsSymbol.GetLength();
1442         cc -= iSysmbolLen - 1;
1443         if (cc < 0 ||
1444             FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol, iSysmbolLen)) {
1445           return FALSE;
1446         }
1447         cc--;
1448         ccf--;
1449         bHavePercentSymbol = TRUE;
1450       } break;
1451       case '8':
1452         return FALSE;
1453       case ',': {
1454         if (cc >= 0) {
1455           cc -= iGroupLen - 1;
1456           if (cc >= 0 &&
1457               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsGroupSymbol,
1458                             iGroupLen) == 0) {
1459             cc--;
1460           } else {
1461             cc += iGroupLen - 1;
1462           }
1463         }
1464         ccf--;
1465       } break;
1466       case '(':
1467         if (str[cc] == L'(') {
1468           bNeg = TRUE;
1469         } else if (str[cc] != L' ') {
1470           return FALSE;
1471         }
1472         cc--;
1473         ccf--;
1474         break;
1475       case ')':
1476         if (str[cc] == L')') {
1477           bNeg = TRUE;
1478         } else if (str[cc] != L' ') {
1479           return FALSE;
1480         }
1481         cc--;
1482         ccf--;
1483         break;
1484       default:
1485         if (strf[ccf] != str[cc]) {
1486           return FALSE;
1487         }
1488         cc--;
1489         ccf--;
1490     }
1491   }
1492   if (cc >= 0) {
1493     return FALSE;
1494   }
1495   if (!bReverseParse) {
1496     ccf = dot_index_f + 1;
1497     cc = (dot_index == len) ? len : dot_index + 1;
1498     coeff = 0.1;
1499     while (cc < len && ccf < lenf) {
1500       switch (strf[ccf]) {
1501         case '\'': {
1502           CFX_WideString wsLiteral = FX_GetLiteralText(strf, ccf, lenf);
1503           int32_t iLiteralLen = wsLiteral.GetLength();
1504           if (cc + iLiteralLen > len ||
1505               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsLiteral,
1506                             iLiteralLen)) {
1507             return FALSE;
1508           }
1509           cc += iLiteralLen;
1510           ccf++;
1511           break;
1512         }
1513         case '9':
1514           if (!FX_IsDigit(str[cc])) {
1515             return FALSE;
1516           }
1517           {
1518             dbRetValue = dbRetValue + (str[cc] - '0') * coeff;
1519             coeff *= 0.1;
1520           }
1521           cc++;
1522           ccf++;
1523           break;
1524         case 'z':
1525           if (FX_IsDigit(str[cc])) {
1526             dbRetValue = dbRetValue + (str[cc] - '0') * coeff;
1527             coeff *= 0.1;
1528             cc++;
1529           }
1530           ccf++;
1531           break;
1532         case 'Z':
1533           if (str[cc] != ' ') {
1534             if (FX_IsDigit(str[cc])) {
1535               dbRetValue = dbRetValue + (str[cc] - '0') * coeff;
1536               coeff *= 0.1;
1537               cc++;
1538             }
1539           } else {
1540             cc++;
1541           }
1542           ccf++;
1543           break;
1544         case 'S':
1545           if (str[cc] == '+' || str[cc] == ' ') {
1546             cc++;
1547           } else {
1548             if (cc + iMinusLen > len ||
1549                 FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
1550               return FALSE;
1551             }
1552             bNeg = TRUE;
1553             cc += iMinusLen;
1554           }
1555           ccf++;
1556           break;
1557         case 's':
1558           if (str[cc] == '+') {
1559             cc++;
1560           } else {
1561             if (cc + iMinusLen > len ||
1562                 FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
1563               return FALSE;
1564             }
1565             bNeg = TRUE;
1566             cc += iMinusLen;
1567           }
1568           ccf++;
1569           break;
1570         case 'E': {
1571           if (cc >= len || (str[cc] != 'E' && str[cc] != 'e')) {
1572             return FALSE;
1573           }
1574           FX_BOOL bExpSign = FALSE;
1575           cc++;
1576           if (cc < len) {
1577             if (str[cc] == '+') {
1578               cc++;
1579             } else if (str[cc] == '-') {
1580               bExpSign = TRUE;
1581               cc++;
1582             }
1583           }
1584           while (cc < len) {
1585             if (!FX_IsDigit(str[cc])) {
1586               break;
1587             }
1588             iExponent = iExponent * 10 + str[cc] - '0';
1589             cc++;
1590           }
1591           iExponent = bExpSign ? -iExponent : iExponent;
1592           ccf++;
1593         } break;
1594         case '$': {
1595           CFX_WideString wsSymbol;
1596           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol,
1597                                      wsSymbol);
1598           int32_t iSymbolLen = wsSymbol.GetLength();
1599           if (cc + iSymbolLen > len ||
1600               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol, iSymbolLen)) {
1601             return FALSE;
1602           }
1603           cc += iSymbolLen;
1604           ccf++;
1605         } break;
1606         case 'c':
1607           if (ccf + 1 < lenf && strf[ccf + 1] == 'r') {
1608             if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {
1609               bNeg = TRUE;
1610               cc += 2;
1611             }
1612             ccf += 2;
1613           }
1614           break;
1615         case 'C':
1616           if (ccf + 1 < lenf && strf[ccf + 1] == 'R') {
1617             if (str[cc] == ' ') {
1618               cc++;
1619             } else if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {
1620               bNeg = TRUE;
1621               cc += 2;
1622             }
1623             ccf += 2;
1624           }
1625           break;
1626         case 'd':
1627           if (ccf + 1 < lenf && strf[ccf + 1] == 'b') {
1628             if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {
1629               bNeg = TRUE;
1630               cc += 2;
1631             }
1632             ccf += 2;
1633           }
1634           break;
1635         case 'D':
1636           if (ccf + 1 < lenf && strf[ccf + 1] == 'B') {
1637             if (str[cc] == ' ') {
1638               cc++;
1639             } else if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {
1640               bNeg = TRUE;
1641               cc += 2;
1642             }
1643             ccf += 2;
1644           }
1645           break;
1646         case '.':
1647         case 'V':
1648         case 'v':
1649           return FALSE;
1650         case '%': {
1651           CFX_WideString wsSymbol;
1652           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
1653           int32_t iSysmbolLen = wsSymbol.GetLength();
1654           if (cc + iSysmbolLen <= len &&
1655               !FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol,
1656                              iSysmbolLen)) {
1657             cc += iSysmbolLen;
1658           }
1659           ccf++;
1660           bHavePercentSymbol = TRUE;
1661         } break;
1662         case '8': {
1663           while (ccf < lenf && strf[ccf] == '8') {
1664             ccf++;
1665           }
1666           while (cc < len && FX_IsDigit(str[cc])) {
1667             dbRetValue = (str[cc] - '0') * coeff + dbRetValue;
1668             coeff *= 0.1;
1669             cc++;
1670           }
1671         } break;
1672         case ',': {
1673           if (cc + iGroupLen <= len &&
1674               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsGroupSymbol,
1675                             iGroupLen) == 0) {
1676             cc += iGroupLen;
1677           }
1678           ccf++;
1679         } break;
1680         case '(':
1681           if (str[cc] == L'(') {
1682             bNeg = TRUE;
1683           } else if (str[cc] != L' ') {
1684             return FALSE;
1685           }
1686           cc++;
1687           ccf++;
1688           break;
1689         case ')':
1690           if (str[cc] == L')') {
1691             bNeg = TRUE;
1692           } else if (str[cc] != L' ') {
1693             return FALSE;
1694           }
1695           cc++;
1696           ccf++;
1697           break;
1698         default:
1699           if (strf[ccf] != str[cc]) {
1700             return FALSE;
1701           }
1702           cc++;
1703           ccf++;
1704       }
1705     }
1706     if (cc != len) {
1707       return FALSE;
1708     }
1709   }
1710   if (iExponent) {
1711     dbRetValue *= FXSYS_pow(10, (FX_FLOAT)iExponent);
1712   }
1713   if (bHavePercentSymbol) {
1714     dbRetValue /= 100.0;
1715   }
1716   if (bNeg) {
1717     dbRetValue = -dbRetValue;
1718   }
1719   fValue = (FX_FLOAT)dbRetValue;
1720   return TRUE;
1721 }
FX_ParseNumString(const CFX_WideString & wsNum,CFX_WideString & wsResult)1722 void FX_ParseNumString(const CFX_WideString& wsNum, CFX_WideString& wsResult) {
1723   int32_t iCount = wsNum.GetLength();
1724   const FX_WCHAR* pStr = (const FX_WCHAR*)wsNum;
1725   FX_WCHAR* pDst = wsResult.GetBuffer(iCount);
1726   int32_t nIndex = 0;
1727   FX_BOOL bMinus = FALSE;
1728   int32_t i = 0;
1729   for (i = 0; i < iCount; i++) {
1730     FX_WCHAR wc = pStr[i];
1731     if (wc == '.') {
1732       break;
1733     }
1734     if ((wc == L'0' || wc == L' ' || wc == '+') && nIndex == 0) {
1735       continue;
1736     }
1737     if (wc == '-') {
1738       pDst[nIndex++] = wc;
1739       bMinus = TRUE;
1740       continue;
1741     }
1742     if (wc == L'0' && nIndex == 1 && bMinus) {
1743       continue;
1744     }
1745     pDst[nIndex++] = wc;
1746   }
1747   if (bMinus && nIndex == 1) {
1748     pDst[nIndex++] = '0';
1749   }
1750   if (nIndex == 0) {
1751     wsResult.ReleaseBuffer(0);
1752     pDst = wsResult.GetBuffer(iCount + 1);
1753     pDst[nIndex++] = '0';
1754   }
1755   int32_t j = 0;
1756   for (j = iCount - 1; j > i; j--) {
1757     FX_WCHAR wc = pStr[j];
1758     if (wc != L'0' && wc != L' ') {
1759       break;
1760     }
1761   }
1762   if (j > i) {
1763     pDst[nIndex++] = '.';
1764     FXSYS_wcsncpy(pDst + nIndex, pStr + i + 1, j - i);
1765     nIndex += j - i;
1766   }
1767   wsResult.ReleaseBuffer(nIndex);
1768 }
ParseNum(const CFX_WideString & wsSrcNum,const CFX_WideString & wsPattern,CFX_WideString & wsValue)1769 FX_BOOL CFX_FormatString::ParseNum(const CFX_WideString& wsSrcNum,
1770                                    const CFX_WideString& wsPattern,
1771                                    CFX_WideString& wsValue) {
1772   wsValue.Empty();
1773   if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty()) {
1774     return FALSE;
1775   }
1776   int32_t dot_index_f = -1;
1777   FX_DWORD dwFormatStyle = 0;
1778   CFX_WideString wsNumFormat;
1779   IFX_Locale* pLocale =
1780       GetNumericFormat(wsPattern, dot_index_f, dwFormatStyle, wsNumFormat);
1781   if (!pLocale || wsNumFormat.IsEmpty()) {
1782     return FALSE;
1783   }
1784   int32_t iExponent = 0;
1785   CFX_WideString wsDotSymbol;
1786   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsDotSymbol);
1787   CFX_WideString wsGroupSymbol;
1788   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping, wsGroupSymbol);
1789   int32_t iGroupLen = wsGroupSymbol.GetLength();
1790   CFX_WideString wsMinus;
1791   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinus);
1792   int32_t iMinusLen = wsMinus.GetLength();
1793   int cc = 0, ccf = 0;
1794   const FX_WCHAR* str = (const FX_WCHAR*)wsSrcNum;
1795   int len = wsSrcNum.GetLength();
1796   const FX_WCHAR* strf = (const FX_WCHAR*)wsNumFormat;
1797   int lenf = wsNumFormat.GetLength();
1798   FX_BOOL bHavePercentSymbol = FALSE;
1799   FX_BOOL bNeg = FALSE;
1800   FX_BOOL bReverseParse = FALSE;
1801   int32_t dot_index = 0;
1802   if (!FX_GetNumericDotIndex(wsSrcNum, wsDotSymbol, dot_index) &&
1803       (dwFormatStyle & FX_NUMSTYLE_DotVorv)) {
1804     bReverseParse = TRUE;
1805   }
1806   bReverseParse = FALSE;
1807   ccf = dot_index_f - 1;
1808   cc = dot_index - 1;
1809   while (ccf >= 0 && cc >= 0) {
1810     switch (strf[ccf]) {
1811       case '\'': {
1812         CFX_WideString wsLiteral = FX_GetLiteralTextReverse(strf, ccf);
1813         int32_t iLiteralLen = wsLiteral.GetLength();
1814         cc -= iLiteralLen - 1;
1815         if (cc < 0 ||
1816             FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsLiteral, iLiteralLen)) {
1817           return FALSE;
1818         }
1819         cc--;
1820         ccf--;
1821         break;
1822       }
1823       case '9':
1824         if (!FX_IsDigit(str[cc])) {
1825           return FALSE;
1826         }
1827         wsValue = CFX_WideStringC(str[cc]) + wsValue;
1828         cc--;
1829         ccf--;
1830         break;
1831       case 'z':
1832         if (FX_IsDigit(str[cc])) {
1833           wsValue = CFX_WideStringC(str[cc]) + wsValue;
1834           cc--;
1835         }
1836         ccf--;
1837         break;
1838       case 'Z':
1839         if (str[cc] != ' ') {
1840           if (FX_IsDigit(str[cc])) {
1841             wsValue = CFX_WideStringC(str[cc]) + wsValue;
1842             cc--;
1843           }
1844         } else {
1845           cc--;
1846         }
1847         ccf--;
1848         break;
1849       case 'S':
1850         if (str[cc] == '+' || str[cc] == ' ') {
1851           cc--;
1852         } else {
1853           cc -= iMinusLen - 1;
1854           if (cc < 0 ||
1855               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
1856             return FALSE;
1857           }
1858           cc--;
1859           bNeg = TRUE;
1860         }
1861         ccf--;
1862         break;
1863       case 's':
1864         if (str[cc] == '+') {
1865           cc--;
1866         } else {
1867           cc -= iMinusLen - 1;
1868           if (cc < 0 ||
1869               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
1870             return FALSE;
1871           }
1872           cc--;
1873           bNeg = TRUE;
1874         }
1875         ccf--;
1876         break;
1877       case 'E': {
1878         if (cc >= dot_index) {
1879           return FALSE;
1880         }
1881         FX_BOOL bExpSign = FALSE;
1882         while (cc >= 0) {
1883           if (str[cc] == 'E' || str[cc] == 'e') {
1884             break;
1885           }
1886           if (FX_IsDigit(str[cc])) {
1887             iExponent = iExponent + (str[cc] - '0') * 10;
1888             cc--;
1889             continue;
1890           } else if (str[cc] == '+') {
1891             cc--;
1892             continue;
1893           } else if (cc - iMinusLen + 1 > 0 &&
1894                      !FXSYS_wcsncmp(str + (cc - iMinusLen + 1),
1895                                     (const FX_WCHAR*)wsMinus, iMinusLen)) {
1896             bExpSign = TRUE;
1897             cc -= iMinusLen;
1898           } else {
1899             return FALSE;
1900           }
1901         }
1902         cc--;
1903         iExponent = bExpSign ? -iExponent : iExponent;
1904         ccf--;
1905       } break;
1906       case '$': {
1907         CFX_WideString wsSymbol;
1908         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);
1909         int32_t iSymbolLen = wsSymbol.GetLength();
1910         cc -= iSymbolLen - 1;
1911         if (cc < 0 ||
1912             FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol, iSymbolLen)) {
1913           return FALSE;
1914         }
1915         cc--;
1916         ccf--;
1917       } break;
1918       case 'r':
1919         if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {
1920           if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {
1921             bNeg = TRUE;
1922             cc -= 2;
1923           }
1924           ccf -= 2;
1925         } else {
1926           ccf--;
1927         }
1928         break;
1929       case 'R':
1930         if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {
1931           if (str[cc] == ' ') {
1932             cc++;
1933           } else if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {
1934             bNeg = TRUE;
1935             cc -= 2;
1936           }
1937           ccf -= 2;
1938         } else {
1939           ccf--;
1940         }
1941         break;
1942       case 'b':
1943         if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {
1944           if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {
1945             bNeg = TRUE;
1946             cc -= 2;
1947           }
1948           ccf -= 2;
1949         } else {
1950           ccf--;
1951         }
1952         break;
1953       case 'B':
1954         if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {
1955           if (str[cc] == ' ') {
1956             cc++;
1957           } else if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {
1958             bNeg = TRUE;
1959             cc -= 2;
1960           }
1961           ccf -= 2;
1962         } else {
1963           ccf--;
1964         }
1965         break;
1966       case '.':
1967       case 'V':
1968       case 'v':
1969         return FALSE;
1970       case '%': {
1971         CFX_WideString wsSymbol;
1972         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
1973         int32_t iSysmbolLen = wsSymbol.GetLength();
1974         cc -= iSysmbolLen - 1;
1975         if (cc < 0 ||
1976             FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol, iSysmbolLen)) {
1977           return FALSE;
1978         }
1979         cc--;
1980         ccf--;
1981         bHavePercentSymbol = TRUE;
1982       } break;
1983       case '8':
1984         return FALSE;
1985       case ',': {
1986         if (cc >= 0) {
1987           cc -= iGroupLen - 1;
1988           if (cc >= 0 &&
1989               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsGroupSymbol,
1990                             iGroupLen) == 0) {
1991             cc--;
1992           } else {
1993             cc += iGroupLen - 1;
1994           }
1995         }
1996         ccf--;
1997       } break;
1998       case '(':
1999         if (str[cc] == L'(') {
2000           bNeg = TRUE;
2001         } else if (str[cc] != L' ') {
2002           return FALSE;
2003         }
2004         cc--;
2005         ccf--;
2006         break;
2007       case ')':
2008         if (str[cc] == L')') {
2009           bNeg = TRUE;
2010         } else if (str[cc] != L' ') {
2011           return FALSE;
2012         }
2013         cc--;
2014         ccf--;
2015         break;
2016       default:
2017         if (strf[ccf] != str[cc]) {
2018           return FALSE;
2019         }
2020         cc--;
2021         ccf--;
2022     }
2023   }
2024   if (cc >= 0) {
2025     if (str[cc] == '-') {
2026       bNeg = TRUE;
2027       cc--;
2028     }
2029     if (cc >= 0) {
2030       return FALSE;
2031     }
2032   }
2033   if (dot_index < len && (dwFormatStyle & FX_NUMSTYLE_DotVorv)) {
2034     wsValue += '.';
2035   }
2036   if (!bReverseParse) {
2037     ccf = dot_index_f + 1;
2038     cc = (dot_index == len) ? len : dot_index + 1;
2039     while (cc < len && ccf < lenf) {
2040       switch (strf[ccf]) {
2041         case '\'': {
2042           CFX_WideString wsLiteral = FX_GetLiteralText(strf, ccf, lenf);
2043           int32_t iLiteralLen = wsLiteral.GetLength();
2044           if (cc + iLiteralLen > len ||
2045               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsLiteral,
2046                             iLiteralLen)) {
2047             return FALSE;
2048           }
2049           cc += iLiteralLen;
2050           ccf++;
2051           break;
2052         }
2053         case '9':
2054           if (!FX_IsDigit(str[cc])) {
2055             return FALSE;
2056           }
2057           { wsValue += str[cc]; }
2058           cc++;
2059           ccf++;
2060           break;
2061         case 'z':
2062           if (FX_IsDigit(str[cc])) {
2063             wsValue += str[cc];
2064             cc++;
2065           }
2066           ccf++;
2067           break;
2068         case 'Z':
2069           if (str[cc] != ' ') {
2070             if (FX_IsDigit(str[cc])) {
2071               wsValue += str[cc];
2072               cc++;
2073             }
2074           } else {
2075             cc++;
2076           }
2077           ccf++;
2078           break;
2079         case 'S':
2080           if (str[cc] == '+' || str[cc] == ' ') {
2081             cc++;
2082           } else {
2083             if (cc + iMinusLen > len ||
2084                 FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
2085               return FALSE;
2086             }
2087             bNeg = TRUE;
2088             cc += iMinusLen;
2089           }
2090           ccf++;
2091           break;
2092         case 's':
2093           if (str[cc] == '+') {
2094             cc++;
2095           } else {
2096             if (cc + iMinusLen > len ||
2097                 FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsMinus, iMinusLen)) {
2098               return FALSE;
2099             }
2100             bNeg = TRUE;
2101             cc += iMinusLen;
2102           }
2103           ccf++;
2104           break;
2105         case 'E': {
2106           if (cc >= len || (str[cc] != 'E' && str[cc] != 'e')) {
2107             return FALSE;
2108           }
2109           FX_BOOL bExpSign = FALSE;
2110           cc++;
2111           if (cc < len) {
2112             if (str[cc] == '+') {
2113               cc++;
2114             } else if (str[cc] == '-') {
2115               bExpSign = TRUE;
2116               cc++;
2117             }
2118           }
2119           while (cc < len) {
2120             if (!FX_IsDigit(str[cc])) {
2121               break;
2122             }
2123             iExponent = iExponent * 10 + str[cc] - '0';
2124             cc++;
2125           }
2126           iExponent = bExpSign ? -iExponent : iExponent;
2127           ccf++;
2128         } break;
2129         case '$': {
2130           CFX_WideString wsSymbol;
2131           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol,
2132                                      wsSymbol);
2133           int32_t iSymbolLen = wsSymbol.GetLength();
2134           if (cc + iSymbolLen > len ||
2135               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol, iSymbolLen)) {
2136             return FALSE;
2137           }
2138           cc += iSymbolLen;
2139           ccf++;
2140         } break;
2141         case 'c':
2142           if (ccf + 1 < lenf && strf[ccf + 1] == 'r') {
2143             if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {
2144               bNeg = TRUE;
2145               cc += 2;
2146             }
2147             ccf += 2;
2148           }
2149           break;
2150         case 'C':
2151           if (ccf + 1 < lenf && strf[ccf + 1] == 'R') {
2152             if (str[cc] == ' ') {
2153               cc++;
2154             } else if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {
2155               bNeg = TRUE;
2156               cc += 2;
2157             }
2158             ccf += 2;
2159           }
2160           break;
2161         case 'd':
2162           if (ccf + 1 < lenf && strf[ccf + 1] == 'b') {
2163             if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {
2164               bNeg = TRUE;
2165               cc += 2;
2166             }
2167             ccf += 2;
2168           }
2169           break;
2170         case 'D':
2171           if (ccf + 1 < lenf && strf[ccf + 1] == 'B') {
2172             if (str[cc] == ' ') {
2173               cc++;
2174             } else if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {
2175               bNeg = TRUE;
2176               cc += 2;
2177             }
2178             ccf += 2;
2179           }
2180           break;
2181         case '.':
2182         case 'V':
2183         case 'v':
2184           return FALSE;
2185         case '%': {
2186           CFX_WideString wsSymbol;
2187           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
2188           int32_t iSysmbolLen = wsSymbol.GetLength();
2189           if (cc + iSysmbolLen <= len &&
2190               !FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsSymbol,
2191                              iSysmbolLen)) {
2192             cc += iSysmbolLen;
2193           }
2194           ccf++;
2195           bHavePercentSymbol = TRUE;
2196         } break;
2197         case '8': {
2198           while (ccf < lenf && strf[ccf] == '8') {
2199             ccf++;
2200           }
2201           while (cc < len && FX_IsDigit(str[cc])) {
2202             wsValue += str[cc];
2203             cc++;
2204           }
2205         } break;
2206         case ',': {
2207           if (cc + iGroupLen <= len &&
2208               FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsGroupSymbol,
2209                             iGroupLen) == 0) {
2210             cc += iGroupLen;
2211           }
2212           ccf++;
2213         } break;
2214         case '(':
2215           if (str[cc] == L'(') {
2216             bNeg = TRUE;
2217           } else if (str[cc] != L' ') {
2218             return FALSE;
2219           }
2220           cc++;
2221           ccf++;
2222           break;
2223         case ')':
2224           if (str[cc] == L')') {
2225             bNeg = TRUE;
2226           } else if (str[cc] != L' ') {
2227             return FALSE;
2228           }
2229           cc++;
2230           ccf++;
2231           break;
2232         default:
2233           if (strf[ccf] != str[cc]) {
2234             return FALSE;
2235           }
2236           cc++;
2237           ccf++;
2238       }
2239     }
2240     if (cc != len) {
2241       return FALSE;
2242     }
2243   }
2244   if (iExponent || bHavePercentSymbol) {
2245     CFX_Decimal decimal = CFX_Decimal(wsValue);
2246     if (iExponent) {
2247       decimal = decimal * CFX_Decimal(FXSYS_pow(10, (FX_FLOAT)iExponent));
2248     }
2249     if (bHavePercentSymbol) {
2250       decimal = decimal / CFX_Decimal(100);
2251     }
2252     wsValue = decimal;
2253   }
2254   if (bNeg) {
2255     wsValue = CFX_WideStringC('-') + wsValue;
2256   }
2257   return TRUE;
2258 }
GetDateTimeFormat(const CFX_WideString & wsPattern,IFX_Locale * & pLocale,CFX_WideString & wsDatePattern,CFX_WideString & wsTimePattern)2259 FX_DATETIMETYPE CFX_FormatString::GetDateTimeFormat(
2260     const CFX_WideString& wsPattern,
2261     IFX_Locale*& pLocale,
2262     CFX_WideString& wsDatePattern,
2263     CFX_WideString& wsTimePattern) {
2264   pLocale = NULL;
2265   CFX_WideString wsTempPattern;
2266   FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown;
2267   int32_t ccf = 0;
2268   int32_t iLenf = wsPattern.GetLength();
2269   const FX_WCHAR* pStr = (const FX_WCHAR*)wsPattern;
2270   int32_t iFindCategory = 0;
2271   FX_BOOL bBraceOpen = FALSE;
2272   while (ccf < iLenf) {
2273     if (pStr[ccf] == '\'') {
2274       int32_t iCurChar = ccf;
2275       FX_GetLiteralText(pStr, ccf, iLenf);
2276       wsTempPattern += CFX_WideStringC(pStr + iCurChar, ccf - iCurChar + 1);
2277     } else if (!bBraceOpen && iFindCategory != 3 &&
2278                FX_Local_Find(gs_wsConstChars, pStr[ccf]) < 0) {
2279       CFX_WideString wsCategory(pStr[ccf]);
2280       ccf++;
2281       while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' &&
2282              pStr[ccf] != '(') {
2283         if (pStr[ccf] == 'T') {
2284           wsDatePattern = wsPattern.Left(ccf);
2285           wsTimePattern = wsPattern.Right(wsPattern.GetLength() - ccf);
2286           wsTimePattern.SetAt(0, ' ');
2287           if (!pLocale) {
2288             pLocale = m_pLocaleMgr->GetDefLocale();
2289           }
2290           return FX_DATETIMETYPE_DateTime;
2291         }
2292         wsCategory += pStr[ccf];
2293         ccf++;
2294       }
2295       if (!(iFindCategory & 1) && wsCategory == FX_WSTRC(L"date")) {
2296         iFindCategory |= 1;
2297         eCategory = FX_LOCALECATEGORY_Date;
2298         if (iFindCategory & 2) {
2299           iFindCategory = 4;
2300         }
2301       } else if (!(iFindCategory & 2) && wsCategory == FX_WSTRC(L"time")) {
2302         iFindCategory |= 2;
2303         eCategory = FX_LOCALECATEGORY_Time;
2304       } else if (wsCategory == FX_WSTRC(L"datetime")) {
2305         iFindCategory = 3;
2306         eCategory = FX_LOCALECATEGORY_DateTime;
2307       } else {
2308         continue;
2309       }
2310       while (ccf < iLenf) {
2311         if (pStr[ccf] == '(') {
2312           ccf++;
2313           CFX_WideString wsLCID;
2314           while (ccf < iLenf && pStr[ccf] != ')') {
2315             wsLCID += pStr[ccf++];
2316           }
2317           pLocale = GetPatternLocale(wsLCID);
2318         } else if (pStr[ccf] == '{') {
2319           bBraceOpen = TRUE;
2320           break;
2321         } else if (pStr[ccf] == '.') {
2322           CFX_WideString wsSubCategory;
2323           ccf++;
2324           while (ccf < iLenf && pStr[ccf] != '(' && pStr[ccf] != '{') {
2325             wsSubCategory += pStr[ccf++];
2326           }
2327           FX_DWORD dwSubHash =
2328               FX_HashCode_String_GetW(wsSubCategory, wsSubCategory.GetLength());
2329           FX_LOCALEDATETIMESUBCATEGORY eSubCategory =
2330               FX_LOCALEDATETIMESUBCATEGORY_Medium;
2331           for (int32_t i = 0; i < g_iFXLocaleDateTimeSubCatCount; i++) {
2332             if (g_FXLocaleDateTimeSubCatData[i].uHash == dwSubHash) {
2333               eSubCategory =
2334                   (FX_LOCALEDATETIMESUBCATEGORY)g_FXLocaleDateTimeSubCatData[i]
2335                       .eSubCategory;
2336               break;
2337             }
2338           }
2339           if (!pLocale) {
2340             pLocale = m_pLocaleMgr->GetDefLocale();
2341           }
2342           FXSYS_assert(pLocale != NULL);
2343           switch (eCategory) {
2344             case FX_LOCALECATEGORY_Date:
2345               pLocale->GetDatePattern(eSubCategory, wsDatePattern);
2346               wsDatePattern = wsTempPattern + wsDatePattern;
2347               break;
2348             case FX_LOCALECATEGORY_Time:
2349               pLocale->GetTimePattern(eSubCategory, wsTimePattern);
2350               wsTimePattern = wsTempPattern + wsTimePattern;
2351               break;
2352             case FX_LOCALECATEGORY_DateTime:
2353               pLocale->GetDatePattern(eSubCategory, wsDatePattern);
2354               wsDatePattern = wsTempPattern + wsDatePattern;
2355               pLocale->GetTimePattern(eSubCategory, wsTimePattern);
2356               break;
2357             default:
2358               break;
2359           }
2360           wsTempPattern.Empty();
2361           continue;
2362         }
2363         ccf++;
2364       }
2365     } else if (pStr[ccf] == '}') {
2366       bBraceOpen = FALSE;
2367       if (!wsTempPattern.IsEmpty()) {
2368         if (eCategory == FX_LOCALECATEGORY_Time) {
2369           wsTimePattern = wsTempPattern;
2370         } else if (eCategory == FX_LOCALECATEGORY_Date) {
2371           wsDatePattern = wsTempPattern;
2372         }
2373         wsTempPattern.Empty();
2374       }
2375     } else {
2376       wsTempPattern += pStr[ccf];
2377     }
2378     ccf++;
2379   }
2380   if (!wsTempPattern.IsEmpty()) {
2381     if (eCategory == FX_LOCALECATEGORY_Date) {
2382       wsDatePattern += wsTempPattern;
2383     } else {
2384       wsTimePattern += wsTempPattern;
2385     }
2386   }
2387   if (!pLocale) {
2388     pLocale = m_pLocaleMgr->GetDefLocale();
2389   }
2390   if (!iFindCategory) {
2391     wsTimePattern.Empty();
2392     wsDatePattern = wsPattern;
2393   }
2394   return (FX_DATETIMETYPE)iFindCategory;
2395 }
FX_ParseLocaleDate(const CFX_WideString & wsDate,const CFX_WideString & wsDatePattern,IFX_Locale * pLocale,CFX_Unitime & datetime,int32_t & cc)2396 static FX_BOOL FX_ParseLocaleDate(const CFX_WideString& wsDate,
2397                                   const CFX_WideString& wsDatePattern,
2398                                   IFX_Locale* pLocale,
2399                                   CFX_Unitime& datetime,
2400                                   int32_t& cc) {
2401   int32_t year = 1900;
2402   int32_t month = 1;
2403   int32_t day = 1;
2404   int32_t ccf = 0;
2405   const FX_WCHAR* str = (const FX_WCHAR*)wsDate;
2406   int32_t len = wsDate.GetLength();
2407   const FX_WCHAR* strf = (const FX_WCHAR*)wsDatePattern;
2408   int32_t lenf = wsDatePattern.GetLength();
2409   while (cc < len && ccf < lenf) {
2410     if (strf[ccf] == '\'') {
2411       CFX_WideString wsLiteral = FX_GetLiteralText(strf, ccf, lenf);
2412       int32_t iLiteralLen = wsLiteral.GetLength();
2413       if (cc + iLiteralLen > len ||
2414           FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsLiteral, iLiteralLen)) {
2415         return FALSE;
2416       }
2417       cc += iLiteralLen;
2418       ccf++;
2419       continue;
2420     } else if (FX_Local_Find(gs_wsDateSymbols, strf[ccf]) < 0) {
2421       if (strf[ccf] != str[cc]) {
2422         return FALSE;
2423       }
2424       cc++;
2425       ccf++;
2426       continue;
2427     }
2428     FX_DWORD dwSymbolNum = 1;
2429     FX_DWORD dwSymbol = strf[ccf++];
2430     while (ccf < lenf && strf[ccf] == dwSymbol) {
2431       ccf++;
2432       dwSymbolNum++;
2433     }
2434     dwSymbol = (dwSymbol << 8) | (dwSymbolNum + '0');
2435     if (dwSymbol == FXBSTR_ID(0, 0, 'D', '1')) {
2436       if (!FX_IsDigit(str[cc])) {
2437         return FALSE;
2438       }
2439       day = str[cc++] - '0';
2440       if (cc < len && FX_IsDigit(str[cc])) {
2441         day = day * 10 + str[cc++] - '0';
2442       }
2443     } else if (dwSymbol == FXBSTR_ID(0, 0, 'D', '2')) {
2444       if (!FX_IsDigit(str[cc])) {
2445         return FALSE;
2446       }
2447       day = str[cc++] - '0';
2448       if (cc < len) {
2449         day = day * 10 + str[cc++] - '0';
2450       }
2451     } else if (dwSymbol == FXBSTR_ID(0, 0, 'J', '1')) {
2452       int i = 0;
2453       while (cc < len && i < 3 && FX_IsDigit(str[cc])) {
2454         cc++;
2455         i++;
2456       }
2457     } else if (dwSymbol == FXBSTR_ID(0, 0, 'J', '3')) {
2458       cc += 3;
2459     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '1')) {
2460       if (!FX_IsDigit(str[cc])) {
2461         return FALSE;
2462       }
2463       month = str[cc++] - '0';
2464       if (cc < len && FX_IsDigit(str[cc])) {
2465         month = month * 10 + str[cc++] - '0';
2466       }
2467     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '2')) {
2468       if (!FX_IsDigit(str[cc])) {
2469         return FALSE;
2470       }
2471       month = str[cc++] - '0';
2472       if (cc < len) {
2473         month = month * 10 + str[cc++] - '0';
2474       }
2475     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '3')) {
2476       CFX_WideString wsMonthNameAbbr;
2477       FX_WORD i = 0;
2478       for (; i < 12; i++) {
2479         pLocale->GetMonthName(i, wsMonthNameAbbr, TRUE);
2480         if (wsMonthNameAbbr.IsEmpty()) {
2481           continue;
2482         }
2483         if (!FXSYS_wcsncmp((const FX_WCHAR*)wsMonthNameAbbr, str + cc,
2484                            wsMonthNameAbbr.GetLength())) {
2485           break;
2486         }
2487       }
2488       if (i < 12) {
2489         cc += wsMonthNameAbbr.GetLength();
2490         month = i + 1;
2491       }
2492     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '4')) {
2493       CFX_WideString wsMonthName;
2494       FX_WORD i = 0;
2495       for (; i < 12; i++) {
2496         pLocale->GetMonthName(i, wsMonthName, FALSE);
2497         if (wsMonthName.IsEmpty()) {
2498           continue;
2499         }
2500         if (!FXSYS_wcsncmp((const FX_WCHAR*)wsMonthName, str + cc,
2501                            wsMonthName.GetLength())) {
2502           break;
2503         }
2504       }
2505       if (i < 12) {
2506         cc += wsMonthName.GetLength();
2507         month = i + 1;
2508       }
2509     } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '1')) {
2510       cc += 1;
2511     } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '3')) {
2512       CFX_WideString wsDayNameAbbr;
2513       FX_WORD i = 0;
2514       for (; i < 7; i++) {
2515         pLocale->GetDayName(i, wsDayNameAbbr, TRUE);
2516         if (wsDayNameAbbr.IsEmpty()) {
2517           continue;
2518         }
2519         if (!FXSYS_wcsncmp((const FX_WCHAR*)wsDayNameAbbr, str + cc,
2520                            wsDayNameAbbr.GetLength())) {
2521           break;
2522         }
2523       }
2524       if (i < 12) {
2525         cc += wsDayNameAbbr.GetLength();
2526       }
2527     } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '4')) {
2528       CFX_WideString wsDayName;
2529       int32_t i = 0;
2530       for (; i < 7; i++) {
2531         pLocale->GetDayName(i, wsDayName, FALSE);
2532         if (wsDayName == L"") {
2533           continue;
2534         }
2535         if (!FXSYS_wcsncmp((const FX_WCHAR*)wsDayName, str + cc,
2536                            wsDayName.GetLength())) {
2537           break;
2538         }
2539       }
2540       if (i < 12) {
2541         cc += wsDayName.GetLength();
2542       }
2543     } else if (dwSymbol == FXBSTR_ID(0, 0, 'e', '1')) {
2544       cc += 1;
2545     } else if (dwSymbol == FXBSTR_ID(0, 0, 'G', '1')) {
2546       cc += 2;
2547     } else if (dwSymbol == FXBSTR_ID(0, 0, 'Y', '2')) {
2548       if (cc + 2 > len) {
2549         return FALSE;
2550       }
2551       if (!FX_IsDigit(str[cc])) {
2552         return FALSE;
2553       }
2554       year = str[cc++] - '0';
2555       if (cc >= len || !FX_IsDigit(str[cc])) {
2556         return FALSE;
2557       }
2558       year = year * 10 + str[cc++] - '0';
2559       if (year <= 29) {
2560         year += 2000;
2561       } else {
2562         year += 1900;
2563       }
2564     } else if (dwSymbol == FXBSTR_ID(0, 0, 'Y', '4')) {
2565       int i = 0;
2566       year = 0;
2567       if (cc + 4 > len) {
2568         return FALSE;
2569       }
2570       while (i < 4) {
2571         if (!FX_IsDigit(str[cc])) {
2572           return FALSE;
2573         }
2574         year = year * 10 + str[cc] - '0';
2575         cc++;
2576         i++;
2577       }
2578     } else if (dwSymbol == FXBSTR_ID(0, 0, 'w', '1')) {
2579       cc += 1;
2580     } else if (dwSymbol == FXBSTR_ID(0, 0, 'W', '2')) {
2581       cc += 2;
2582     }
2583   }
2584   if (cc < len) {
2585     return FALSE;
2586   }
2587   CFX_Unitime ut;
2588   ut.Set(year, month, day);
2589   datetime = datetime + ut;
2590   return cc;
2591 }
FX_ResolveZone(uint8_t & wHour,uint8_t & wMinute,FX_TIMEZONE tzDiff,IFX_Locale * pLocale)2592 static void FX_ResolveZone(uint8_t& wHour,
2593                            uint8_t& wMinute,
2594                            FX_TIMEZONE tzDiff,
2595                            IFX_Locale* pLocale) {
2596   int32_t iMinuteDiff = wHour * 60 + wMinute;
2597   FX_TIMEZONE tzLocale;
2598   pLocale->GetTimeZone(tzLocale);
2599   iMinuteDiff += tzLocale.tzHour * 60 +
2600                  (tzLocale.tzHour < 0 ? -tzLocale.tzMinute : tzLocale.tzMinute);
2601   iMinuteDiff -= tzDiff.tzHour * 60 +
2602                  (tzDiff.tzHour < 0 ? -tzDiff.tzMinute : tzDiff.tzMinute);
2603   while (iMinuteDiff > 1440) {
2604     iMinuteDiff -= 1440;
2605   }
2606   while (iMinuteDiff < 0) {
2607     iMinuteDiff += 1440;
2608   }
2609   wHour = iMinuteDiff / 60;
2610   wMinute = iMinuteDiff % 60;
2611 }
FX_ParseLocaleTime(const CFX_WideString & wsTime,const CFX_WideString & wsTimePattern,IFX_Locale * pLocale,CFX_Unitime & datetime,int32_t & cc)2612 static FX_BOOL FX_ParseLocaleTime(const CFX_WideString& wsTime,
2613                                   const CFX_WideString& wsTimePattern,
2614                                   IFX_Locale* pLocale,
2615                                   CFX_Unitime& datetime,
2616                                   int32_t& cc) {
2617   uint8_t hour = 0;
2618   uint8_t minute = 0;
2619   uint8_t second = 0;
2620   FX_WORD millisecond = 0;
2621   int32_t ccf = 0;
2622   const FX_WCHAR* str = (const FX_WCHAR*)wsTime;
2623   int len = wsTime.GetLength();
2624   const FX_WCHAR* strf = (const FX_WCHAR*)wsTimePattern;
2625   int lenf = wsTimePattern.GetLength();
2626   FX_BOOL bHasA = FALSE;
2627   FX_BOOL bPM = FALSE;
2628   while (cc < len && ccf < lenf) {
2629     if (strf[ccf] == '\'') {
2630       CFX_WideString wsLiteral = FX_GetLiteralText(strf, ccf, lenf);
2631       int32_t iLiteralLen = wsLiteral.GetLength();
2632       if (cc + iLiteralLen > len ||
2633           FXSYS_wcsncmp(str + cc, (const FX_WCHAR*)wsLiteral, iLiteralLen)) {
2634         return FALSE;
2635       }
2636       cc += iLiteralLen;
2637       ccf++;
2638       continue;
2639     } else if (FX_Local_Find(gs_wsTimeSymbols, strf[ccf]) == -1) {
2640       if (strf[ccf] != str[cc]) {
2641         return FALSE;
2642       }
2643       cc++;
2644       ccf++;
2645       continue;
2646     }
2647     FX_DWORD dwSymbolNum = 1;
2648     FX_DWORD dwSymbol = strf[ccf++];
2649     while (ccf < lenf && strf[ccf] == dwSymbol) {
2650       ccf++;
2651       dwSymbolNum++;
2652     }
2653     dwSymbol = (dwSymbol << 8) | (dwSymbolNum + '0');
2654     if (dwSymbol == FXBSTR_ID(0, 0, 'k', '1') ||
2655         dwSymbol == FXBSTR_ID(0, 0, 'H', '1') ||
2656         dwSymbol == FXBSTR_ID(0, 0, 'h', '1') ||
2657         dwSymbol == FXBSTR_ID(0, 0, 'K', '1')) {
2658       if (!FX_IsDigit(str[cc])) {
2659         return FALSE;
2660       }
2661       hour = str[cc++] - '0';
2662       if (cc < len && FX_IsDigit(str[cc])) {
2663         hour = hour * 10 + str[cc++] - '0';
2664       }
2665       if (dwSymbol == FXBSTR_ID(0, 0, 'K', '1') && hour == 24) {
2666         hour = 0;
2667       }
2668     } else if (dwSymbol == FXBSTR_ID(0, 0, 'k', '2') ||
2669                dwSymbol == FXBSTR_ID(0, 0, 'H', '2') ||
2670                dwSymbol == FXBSTR_ID(0, 0, 'h', '2') ||
2671                dwSymbol == FXBSTR_ID(0, 0, 'K', '2')) {
2672       if (!FX_IsDigit(str[cc])) {
2673         return FALSE;
2674       }
2675       hour = str[cc++] - '0';
2676       if (cc >= len) {
2677         return FALSE;
2678       }
2679       if (!FX_IsDigit(str[cc])) {
2680         return FALSE;
2681       }
2682       hour = hour * 10 + str[cc++] - '0';
2683       if (dwSymbol == FXBSTR_ID(0, 0, 'K', '2') && hour == 24) {
2684         hour = 0;
2685       }
2686     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '1')) {
2687       if (!FX_IsDigit(str[cc])) {
2688         return FALSE;
2689       }
2690       minute = str[cc++] - '0';
2691       if (cc < len && FX_IsDigit(str[cc])) {
2692         minute = minute * 10 + str[cc++] - '0';
2693       }
2694     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '2')) {
2695       if (!FX_IsDigit(str[cc])) {
2696         return FALSE;
2697       }
2698       minute = str[cc++] - '0';
2699       if (cc >= len) {
2700         return FALSE;
2701       }
2702       if (!FX_IsDigit(str[cc])) {
2703         return FALSE;
2704       }
2705       minute = minute * 10 + str[cc++] - '0';
2706     } else if (dwSymbol == FXBSTR_ID(0, 0, 'S', '1')) {
2707       if (!FX_IsDigit(str[cc])) {
2708         return FALSE;
2709       }
2710       second = str[cc++] - '0';
2711       if (cc < len && FX_IsDigit(str[cc])) {
2712         second = second * 10 + str[cc++] - '0';
2713       }
2714     } else if (dwSymbol == FXBSTR_ID(0, 0, 'S', '2')) {
2715       if (!FX_IsDigit(str[cc])) {
2716         return FALSE;
2717       }
2718       second = str[cc++] - '0';
2719       if (cc >= len) {
2720         return FALSE;
2721       }
2722       if (!FX_IsDigit(str[cc])) {
2723         return FALSE;
2724       }
2725       second = second * 10 + str[cc++] - '0';
2726     } else if (dwSymbol == FXBSTR_ID(0, 0, 'F', '3')) {
2727       if (cc + 3 >= len) {
2728         return FALSE;
2729       }
2730       int i = 0;
2731       while (i < 3) {
2732         if (!FX_IsDigit(str[cc])) {
2733           return FALSE;
2734         }
2735         millisecond = millisecond * 10 + str[cc++] - '0';
2736         i++;
2737       }
2738     } else if (dwSymbol == FXBSTR_ID(0, 0, 'A', '1')) {
2739       CFX_WideString wsAM;
2740       pLocale->GetMeridiemName(wsAM, TRUE);
2741       CFX_WideString wsPM;
2742       pLocale->GetMeridiemName(wsPM, FALSE);
2743       if ((cc + wsAM.GetLength() <= len) &&
2744           (CFX_WideStringC(str + cc, wsAM.GetLength()) == wsAM)) {
2745         cc += wsAM.GetLength();
2746         bHasA = TRUE;
2747       } else if ((cc + wsPM.GetLength() <= len) &&
2748                  (CFX_WideStringC(str + cc, wsPM.GetLength()) == wsPM)) {
2749         cc += wsPM.GetLength();
2750         bHasA = TRUE;
2751         bPM = TRUE;
2752       }
2753     } else if (dwSymbol == FXBSTR_ID(0, 0, 'Z', '1')) {
2754       if (cc + 3 > len) {
2755         continue;
2756       }
2757       FX_DWORD dwHash = str[cc++];
2758       dwHash = (dwHash << 8) | str[cc++];
2759       dwHash = (dwHash << 8) | str[cc++];
2760       if (dwHash == FXBSTR_ID(0, 'G', 'M', 'T')) {
2761         FX_TIMEZONE tzDiff;
2762         tzDiff.tzHour = 0;
2763         tzDiff.tzMinute = 0;
2764         if (cc < len && (str[cc] == '-' || str[cc] == '+')) {
2765           cc += FX_ParseTimeZone(str + cc, len - cc, tzDiff);
2766         }
2767         FX_ResolveZone(hour, minute, tzDiff, pLocale);
2768       } else {
2769         FX_LPCLOCALETIMEZONEINFO pTimeZoneInfo = NULL;
2770         int32_t iStart = 0, iEnd = g_iFXLocaleTimeZoneCount - 1;
2771         do {
2772           int32_t iMid = (iStart + iEnd) / 2;
2773           FX_LPCLOCALETIMEZONEINFO pInfo = g_FXLocaleTimeZoneData + iMid;
2774           if (dwHash == pInfo->uHash) {
2775             pTimeZoneInfo = pInfo;
2776             break;
2777           } else if (dwHash < pInfo->uHash) {
2778             iEnd = iMid - 1;
2779           } else {
2780             iStart = iMid + 1;
2781           }
2782         } while (iStart <= iEnd);
2783         if (pTimeZoneInfo) {
2784           hour += pTimeZoneInfo->iHour;
2785           minute += pTimeZoneInfo->iHour > 0 ? pTimeZoneInfo->iMinute
2786                                              : -pTimeZoneInfo->iMinute;
2787         }
2788       }
2789     } else if (dwSymbol == FXBSTR_ID(0, 0, 'z', '1')) {
2790       if (str[cc] != 'Z') {
2791         FX_TIMEZONE tzDiff;
2792         cc += FX_ParseTimeZone(str + cc, len - cc, tzDiff);
2793         FX_ResolveZone(hour, minute, tzDiff, pLocale);
2794       } else {
2795         cc++;
2796       }
2797     }
2798   }
2799   if (bHasA) {
2800     if (bPM) {
2801       hour += 12;
2802       if (hour == 24) {
2803         hour = 12;
2804       }
2805     } else {
2806       if (hour == 12) {
2807         hour = 0;
2808       }
2809     }
2810   }
2811   CFX_Unitime ut;
2812   ut.Set(0, 0, 0, hour, minute, second, millisecond);
2813   datetime = datetime + ut;
2814   return cc;
2815 }
ParseDateTime(const CFX_WideString & wsSrcDateTime,const CFX_WideString & wsPattern,FX_DATETIMETYPE eDateTimeType,CFX_Unitime & dtValue)2816 FX_BOOL CFX_FormatString::ParseDateTime(const CFX_WideString& wsSrcDateTime,
2817                                         const CFX_WideString& wsPattern,
2818                                         FX_DATETIMETYPE eDateTimeType,
2819                                         CFX_Unitime& dtValue) {
2820   dtValue.Set(0);
2821   if (wsSrcDateTime.IsEmpty() || wsPattern.IsEmpty()) {
2822     return FALSE;
2823   }
2824   CFX_WideString wsDatePattern, wsTimePattern;
2825   IFX_Locale* pLocale = NULL;
2826   FX_DATETIMETYPE eCategory =
2827       GetDateTimeFormat(wsPattern, pLocale, wsDatePattern, wsTimePattern);
2828   if (!pLocale) {
2829     return FALSE;
2830   }
2831   if (eCategory == FX_DATETIMETYPE_Unknown) {
2832     eCategory = eDateTimeType;
2833   }
2834   if (eCategory == FX_DATETIMETYPE_Unknown) {
2835     return FALSE;
2836   }
2837   if (eCategory == FX_DATETIMETYPE_TimeDate) {
2838     int32_t iStart = 0;
2839     if (!FX_ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue,
2840                             iStart)) {
2841       return FALSE;
2842     }
2843     if (!FX_ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue,
2844                             iStart)) {
2845       return FALSE;
2846     }
2847   } else {
2848     int32_t iStart = 0;
2849     if ((eCategory & FX_DATETIMETYPE_Date) &&
2850         !FX_ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue,
2851                             iStart)) {
2852       return FALSE;
2853     }
2854     if ((eCategory & FX_DATETIMETYPE_Time) &&
2855         !FX_ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue,
2856                             iStart)) {
2857       return FALSE;
2858     }
2859   }
2860   return TRUE;
2861 }
ParseZero(const CFX_WideString & wsSrcText,const CFX_WideString & wsPattern)2862 FX_BOOL CFX_FormatString::ParseZero(const CFX_WideString& wsSrcText,
2863                                     const CFX_WideString& wsPattern) {
2864   CFX_WideString wsTextFormat;
2865   GetTextFormat(wsPattern, FX_WSTRC(L"zero"), wsTextFormat);
2866   int32_t iText = 0, iPattern = 0;
2867   const FX_WCHAR* pStrText = (const FX_WCHAR*)wsSrcText;
2868   int32_t iLenText = wsSrcText.GetLength();
2869   const FX_WCHAR* pStrPattern = (const FX_WCHAR*)wsTextFormat;
2870   int32_t iLenPattern = wsTextFormat.GetLength();
2871   while (iPattern < iLenPattern && iText < iLenText) {
2872     if (pStrPattern[iPattern] == '\'') {
2873       CFX_WideString wsLiteral =
2874           FX_GetLiteralText(pStrPattern, iPattern, iLenPattern);
2875       int32_t iLiteralLen = wsLiteral.GetLength();
2876       if (iText + iLiteralLen > iLenText ||
2877           FXSYS_wcsncmp(pStrText + iText, (const FX_WCHAR*)wsLiteral,
2878                         iLiteralLen)) {
2879         return FALSE;
2880       }
2881       iText += iLiteralLen;
2882       iPattern++;
2883       continue;
2884     } else if (pStrPattern[iPattern] != pStrText[iText]) {
2885       return FALSE;
2886     } else {
2887       iText++;
2888       iPattern++;
2889     }
2890   }
2891   return iPattern == iLenPattern && iText == iLenText;
2892 }
ParseNull(const CFX_WideString & wsSrcText,const CFX_WideString & wsPattern)2893 FX_BOOL CFX_FormatString::ParseNull(const CFX_WideString& wsSrcText,
2894                                     const CFX_WideString& wsPattern) {
2895   CFX_WideString wsTextFormat;
2896   GetTextFormat(wsPattern, FX_WSTRC(L"null"), wsTextFormat);
2897   int32_t iText = 0, iPattern = 0;
2898   const FX_WCHAR* pStrText = (const FX_WCHAR*)wsSrcText;
2899   int32_t iLenText = wsSrcText.GetLength();
2900   const FX_WCHAR* pStrPattern = (const FX_WCHAR*)wsTextFormat;
2901   int32_t iLenPattern = wsTextFormat.GetLength();
2902   while (iPattern < iLenPattern && iText < iLenText) {
2903     if (pStrPattern[iPattern] == '\'') {
2904       CFX_WideString wsLiteral =
2905           FX_GetLiteralText(pStrPattern, iPattern, iLenPattern);
2906       int32_t iLiteralLen = wsLiteral.GetLength();
2907       if (iText + iLiteralLen > iLenText ||
2908           FXSYS_wcsncmp(pStrText + iText, (const FX_WCHAR*)wsLiteral,
2909                         iLiteralLen)) {
2910         return FALSE;
2911       }
2912       iText += iLiteralLen;
2913       iPattern++;
2914       continue;
2915     } else if (pStrPattern[iPattern] != pStrText[iText]) {
2916       return FALSE;
2917     } else {
2918       iText++;
2919       iPattern++;
2920     }
2921   }
2922   return iPattern == iLenPattern && iText == iLenText;
2923 }
FormatText(const CFX_WideString & wsSrcText,const CFX_WideString & wsPattern,CFX_WideString & wsOutput)2924 FX_BOOL CFX_FormatString::FormatText(const CFX_WideString& wsSrcText,
2925                                      const CFX_WideString& wsPattern,
2926                                      CFX_WideString& wsOutput) {
2927   if (wsPattern.IsEmpty()) {
2928     return FALSE;
2929   }
2930   int32_t iLenText = wsSrcText.GetLength();
2931   if (iLenText == 0) {
2932     return FALSE;
2933   }
2934   CFX_WideString wsTextFormat;
2935   GetTextFormat(wsPattern, FX_WSTRC(L"text"), wsTextFormat);
2936   int32_t iText = 0, iPattern = 0;
2937   const FX_WCHAR* pStrText = (const FX_WCHAR*)wsSrcText;
2938   const FX_WCHAR* pStrPattern = (const FX_WCHAR*)wsTextFormat;
2939   int32_t iLenPattern = wsTextFormat.GetLength();
2940   while (iPattern < iLenPattern) {
2941     switch (pStrPattern[iPattern]) {
2942       case '\'': {
2943         wsOutput += FX_GetLiteralText(pStrPattern, iPattern, iLenPattern);
2944         iPattern++;
2945         break;
2946       }
2947       case 'A':
2948         if (iText >= iLenText || !FX_IsAlpha(pStrText[iText])) {
2949           return FALSE;
2950         }
2951         wsOutput += pStrText[iText++];
2952         iPattern++;
2953         break;
2954       case 'X':
2955         if (iText >= iLenText) {
2956           return FALSE;
2957         }
2958         wsOutput += pStrText[iText++];
2959         iPattern++;
2960         break;
2961       case 'O':
2962       case '0':
2963         if (iText >= iLenText ||
2964             (!FX_IsDigit(pStrText[iText]) && !FX_IsAlpha(pStrText[iText]))) {
2965           return FALSE;
2966         }
2967         wsOutput += pStrText[iText++];
2968         iPattern++;
2969         break;
2970       case '9':
2971         if (iText >= iLenText || !FX_IsDigit(pStrText[iText])) {
2972           return FALSE;
2973         }
2974         wsOutput += pStrText[iText++];
2975         iPattern++;
2976         break;
2977       default:
2978         wsOutput += pStrPattern[iPattern++];
2979         break;
2980     }
2981   }
2982   return iText == iLenText;
2983 }
FX_GetNumTrailingLimit(const CFX_WideString & wsFormat,int iDotPos,FX_BOOL & bTrimTailZeros)2984 static int32_t FX_GetNumTrailingLimit(const CFX_WideString& wsFormat,
2985                                       int iDotPos,
2986                                       FX_BOOL& bTrimTailZeros) {
2987   if (iDotPos < 0) {
2988     return 0;
2989   }
2990   int32_t iCount = wsFormat.GetLength();
2991   int32_t iTreading = 0;
2992   for (iDotPos++; iDotPos < iCount; iDotPos++) {
2993     FX_WCHAR wc = wsFormat[iDotPos];
2994     if (wc == L'z' || wc == L'9' || wc == 'Z') {
2995       iTreading++;
2996       bTrimTailZeros = (wc == L'9' ? FALSE : TRUE);
2997     }
2998   }
2999   return iTreading;
3000 }
FormatStrNum(const CFX_WideStringC & wsInputNum,const CFX_WideString & wsPattern,CFX_WideString & wsOutput)3001 FX_BOOL CFX_FormatString::FormatStrNum(const CFX_WideStringC& wsInputNum,
3002                                        const CFX_WideString& wsPattern,
3003                                        CFX_WideString& wsOutput) {
3004   if (wsInputNum.IsEmpty() || wsPattern.IsEmpty()) {
3005     return FALSE;
3006   }
3007   int32_t dot_index_f = -1;
3008   FX_DWORD dwNumStyle = 0;
3009   CFX_WideString wsNumFormat;
3010   IFX_Locale* pLocale =
3011       GetNumericFormat(wsPattern, dot_index_f, dwNumStyle, wsNumFormat);
3012   if (!pLocale || wsNumFormat.IsEmpty()) {
3013     return FALSE;
3014   }
3015   int32_t cc = 0, ccf = 0;
3016   const FX_WCHAR* strf = (const FX_WCHAR*)wsNumFormat;
3017   int lenf = wsNumFormat.GetLength();
3018   CFX_WideString wsSrcNum = wsInputNum;
3019   wsSrcNum.TrimLeft('0');
3020   if (wsSrcNum.IsEmpty() || wsSrcNum[0] == '.') {
3021     wsSrcNum.Insert(0, '0');
3022   }
3023   CFX_Decimal decimal = CFX_Decimal(wsSrcNum);
3024   if (dwNumStyle & FX_NUMSTYLE_Percent) {
3025     decimal = decimal * CFX_Decimal(100);
3026     wsSrcNum = decimal;
3027   }
3028   int32_t exponent = 0;
3029   if (dwNumStyle & FX_NUMSTYLE_Exponent) {
3030     int fixed_count = 0;
3031     while (ccf < dot_index_f) {
3032       switch (strf[ccf]) {
3033         case '\'':
3034           FX_GetLiteralText(strf, ccf, dot_index_f);
3035           break;
3036         case '9':
3037         case 'z':
3038         case 'Z':
3039           fixed_count++;
3040           break;
3041       }
3042       ccf++;
3043     }
3044     int threshold = 1;
3045     while (fixed_count > 1) {
3046       threshold *= 10;
3047       fixed_count--;
3048     }
3049     if (decimal != CFX_Decimal(0)) {
3050       if (decimal < CFX_Decimal(threshold)) {
3051         decimal = decimal * CFX_Decimal(10);
3052         exponent = -1;
3053         while (decimal < CFX_Decimal(threshold)) {
3054           decimal = decimal * CFX_Decimal(10);
3055           exponent -= 1;
3056         }
3057       } else if (decimal > CFX_Decimal(threshold)) {
3058         threshold *= 10;
3059         while (decimal > CFX_Decimal(threshold)) {
3060           decimal = decimal / CFX_Decimal(10);
3061           exponent += 1;
3062         }
3063       }
3064     }
3065   }
3066   FX_BOOL bTrimTailZeros = FALSE;
3067   int32_t iTreading =
3068       FX_GetNumTrailingLimit(wsNumFormat, dot_index_f, bTrimTailZeros);
3069   int32_t scale = decimal.GetScale();
3070   if (iTreading < scale) {
3071     decimal.SetScale(iTreading);
3072     wsSrcNum = decimal;
3073   }
3074   if (bTrimTailZeros && scale > 0 && iTreading > 0) {
3075     wsSrcNum.TrimRight(L"0");
3076     wsSrcNum.TrimRight(L".");
3077   }
3078   CFX_WideString wsGroupSymbol;
3079   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping, wsGroupSymbol);
3080   FX_BOOL bNeg = FALSE;
3081   if (wsSrcNum[0] == '-') {
3082     bNeg = TRUE;
3083     wsSrcNum.Delete(0, 1);
3084   }
3085   FX_BOOL bAddNeg = FALSE;
3086   const FX_WCHAR* str = (const FX_WCHAR*)wsSrcNum;
3087   int len = wsSrcNum.GetLength();
3088   int dot_index = wsSrcNum.Find('.');
3089   if (dot_index == -1) {
3090     dot_index = len;
3091   }
3092   ccf = dot_index_f - 1;
3093   cc = dot_index - 1;
3094   while (ccf >= 0) {
3095     switch (strf[ccf]) {
3096       case '9':
3097         if (cc >= 0) {
3098           if (!FX_IsDigit(str[cc])) {
3099             return FALSE;
3100           }
3101           wsOutput = CFX_WideStringC(str[cc]) + wsOutput;
3102           cc--;
3103         } else {
3104           wsOutput = CFX_WideStringC(L'0') + wsOutput;
3105         }
3106         ccf--;
3107         break;
3108       case 'z':
3109         if (cc >= 0) {
3110           if (!FX_IsDigit(str[cc])) {
3111             return FALSE;
3112           }
3113           if (str[0] != '0') {
3114             wsOutput = CFX_WideStringC(str[cc]) + wsOutput;
3115           }
3116           cc--;
3117         }
3118         ccf--;
3119         break;
3120       case 'Z':
3121         if (cc >= 0) {
3122           if (!FX_IsDigit(str[cc])) {
3123             return FALSE;
3124           }
3125           if (str[0] == '0') {
3126             wsOutput = CFX_WideStringC(L' ') + wsOutput;
3127           } else {
3128             wsOutput = CFX_WideStringC(str[cc]) + wsOutput;
3129           }
3130           cc--;
3131         } else {
3132           wsOutput = CFX_WideStringC(L' ') + wsOutput;
3133         }
3134         ccf--;
3135         break;
3136       case 'S':
3137         if (bNeg) {
3138           CFX_WideString wsMinusSymbol;
3139           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusSymbol);
3140           wsOutput = wsMinusSymbol + wsOutput;
3141           bAddNeg = TRUE;
3142         } else {
3143           wsOutput = CFX_WideStringC(L' ') + wsOutput;
3144         }
3145         ccf--;
3146         break;
3147       case 's':
3148         if (bNeg) {
3149           CFX_WideString wsMinusSymbol;
3150           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusSymbol);
3151           wsOutput = wsMinusSymbol + wsOutput;
3152           bAddNeg = TRUE;
3153         }
3154         ccf--;
3155         break;
3156       case 'E': {
3157         CFX_WideString wsExp;
3158         wsExp.Format(L"E%+d", exponent);
3159         wsOutput = wsExp + wsOutput;
3160       }
3161         ccf--;
3162         break;
3163       case '$': {
3164         CFX_WideString wsSymbol;
3165         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);
3166         wsOutput = wsSymbol + wsOutput;
3167       }
3168         ccf--;
3169         break;
3170       case 'r':
3171         if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {
3172           if (bNeg) {
3173             wsOutput = L"CR" + wsOutput;
3174           }
3175           ccf -= 2;
3176           bAddNeg = TRUE;
3177         }
3178         break;
3179       case 'R':
3180         if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {
3181           if (bNeg) {
3182             wsOutput = L"CR" + wsOutput;
3183           } else {
3184             wsOutput = L"  " + wsOutput;
3185           }
3186           ccf -= 2;
3187           bAddNeg = TRUE;
3188         }
3189         break;
3190       case 'b':
3191         if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {
3192           if (bNeg) {
3193             wsOutput = L"db" + wsOutput;
3194           }
3195           ccf -= 2;
3196           bAddNeg = TRUE;
3197         }
3198         break;
3199       case 'B':
3200         if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {
3201           if (bNeg) {
3202             wsOutput = L"DB" + wsOutput;
3203           } else {
3204             wsOutput = L"  " + wsOutput;
3205           }
3206           ccf -= 2;
3207           bAddNeg = TRUE;
3208         }
3209         break;
3210       case '%': {
3211         CFX_WideString wsSymbol;
3212         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
3213         wsOutput = wsSymbol + wsOutput;
3214       }
3215         ccf--;
3216         break;
3217       case ',':
3218         if (cc >= 0) {
3219           wsOutput = wsGroupSymbol + wsOutput;
3220         }
3221         ccf--;
3222         break;
3223       case '(':
3224         if (bNeg) {
3225           wsOutput = L"(" + wsOutput;
3226         } else {
3227           wsOutput = L" " + wsOutput;
3228         }
3229         bAddNeg = TRUE;
3230         ccf--;
3231         break;
3232       case ')':
3233         if (bNeg) {
3234           wsOutput = L")" + wsOutput;
3235         } else {
3236           wsOutput = L" " + wsOutput;
3237         }
3238         ccf--;
3239         break;
3240       case '\'':
3241         wsOutput = FX_GetLiteralTextReverse(strf, ccf) + wsOutput;
3242         ccf--;
3243         break;
3244       default:
3245         wsOutput = CFX_WideStringC(strf[ccf]) + wsOutput;
3246         ccf--;
3247     }
3248   }
3249   if (cc >= 0) {
3250     int nPos = dot_index % 3;
3251     wsOutput.Empty();
3252     for (int32_t i = 0; i < dot_index; i++) {
3253       if (i % 3 == nPos && i != 0) {
3254         wsOutput += wsGroupSymbol;
3255       }
3256       wsOutput += wsSrcNum[i];
3257     }
3258     if (dot_index < len) {
3259       CFX_WideString wsSymbol;
3260       pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsSymbol);
3261       wsOutput += wsSymbol;
3262       wsOutput += wsSrcNum.Right(len - dot_index - 1);
3263     }
3264     if (bNeg) {
3265       CFX_WideString wsMinusymbol;
3266       pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusymbol);
3267       wsOutput = wsMinusymbol + wsOutput;
3268     }
3269     return FALSE;
3270   }
3271   if (dot_index_f == wsNumFormat.GetLength()) {
3272     if (!bAddNeg && bNeg) {
3273       CFX_WideString wsMinusymbol;
3274       pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusymbol);
3275       wsOutput = wsMinusymbol + wsOutput;
3276     }
3277     return TRUE;
3278   }
3279   CFX_WideString wsDotSymbol;
3280   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsDotSymbol);
3281   if (strf[dot_index_f] == 'V') {
3282     wsOutput += wsDotSymbol;
3283   } else if (strf[dot_index_f] == '.') {
3284     if (dot_index < len) {
3285       wsOutput += wsDotSymbol;
3286     } else {
3287       if (strf[dot_index_f + 1] == '9' || strf[dot_index_f + 1] == 'Z') {
3288         wsOutput += wsDotSymbol;
3289       }
3290     }
3291   }
3292   ccf = dot_index_f + 1;
3293   cc = dot_index + 1;
3294   while (ccf < lenf) {
3295     switch (strf[ccf]) {
3296       case '\'':
3297         wsOutput += FX_GetLiteralText(strf, ccf, lenf);
3298         ccf++;
3299         break;
3300       case '9':
3301         if (cc < len) {
3302           if (!FX_IsDigit(str[cc])) {
3303             return FALSE;
3304           }
3305           wsOutput += str[cc];
3306           cc++;
3307         } else {
3308           wsOutput += L'0';
3309         }
3310         ccf++;
3311         break;
3312       case 'z':
3313         if (cc < len) {
3314           if (!FX_IsDigit(str[cc])) {
3315             return FALSE;
3316           }
3317           wsOutput += str[cc];
3318           cc++;
3319         }
3320         ccf++;
3321         break;
3322       case 'Z':
3323         if (cc < len) {
3324           if (!FX_IsDigit(str[cc])) {
3325             return FALSE;
3326           }
3327           wsOutput += str[cc];
3328           cc++;
3329         } else {
3330           wsOutput += L'0';
3331         }
3332         ccf++;
3333         break;
3334       case 'E': {
3335         CFX_WideString wsExp;
3336         wsExp.Format(L"E%+d", exponent);
3337         wsOutput += wsExp;
3338       }
3339         ccf++;
3340         break;
3341       case '$': {
3342         CFX_WideString wsSymbol;
3343         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);
3344         wsOutput += wsSymbol;
3345       }
3346         ccf++;
3347         break;
3348       case 'c':
3349         if (ccf + 1 < lenf && strf[ccf + 1] == 'r') {
3350           if (bNeg) {
3351             wsOutput += L"CR";
3352           }
3353           ccf += 2;
3354           bAddNeg = TRUE;
3355         }
3356         break;
3357       case 'C':
3358         if (ccf + 1 < lenf && strf[ccf + 1] == 'R') {
3359           if (bNeg) {
3360             wsOutput += L"CR";
3361           } else {
3362             wsOutput += L"  ";
3363           }
3364           ccf += 2;
3365           bAddNeg = TRUE;
3366         }
3367         break;
3368       case 'd':
3369         if (ccf + 1 < lenf && strf[ccf + 1] == 'b') {
3370           if (bNeg) {
3371             wsOutput += L"db";
3372           }
3373           ccf += 2;
3374           bAddNeg = TRUE;
3375         }
3376         break;
3377       case 'D':
3378         if (ccf + 1 < lenf && strf[ccf + 1] == 'B') {
3379           if (bNeg) {
3380             wsOutput += L"DB";
3381           } else {
3382             wsOutput += L"  ";
3383           }
3384           ccf += 2;
3385           bAddNeg = TRUE;
3386         }
3387         break;
3388       case '%': {
3389         CFX_WideString wsSymbol;
3390         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
3391         wsOutput += wsSymbol;
3392       }
3393         ccf++;
3394         break;
3395       case '8': {
3396         while (ccf < lenf && strf[ccf] == '8') {
3397           ccf++;
3398         }
3399         while (cc < len && FX_IsDigit(str[cc])) {
3400           wsOutput += str[cc];
3401           cc++;
3402         }
3403       } break;
3404       case ',':
3405         wsOutput += wsGroupSymbol;
3406         ccf++;
3407         break;
3408       case '(':
3409         if (bNeg) {
3410           wsOutput += '(';
3411         } else {
3412           wsOutput += ' ';
3413         }
3414         bAddNeg = TRUE;
3415         ccf++;
3416         break;
3417       case ')':
3418         if (bNeg) {
3419           wsOutput += ')';
3420         } else {
3421           wsOutput += ' ';
3422         }
3423         ccf++;
3424         break;
3425       default:
3426         ccf++;
3427     }
3428   }
3429   if (!bAddNeg && bNeg) {
3430     CFX_WideString wsMinusymbol;
3431     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusymbol);
3432     wsOutput =
3433         wsMinusymbol + wsOutput[0] + wsOutput.Mid(1, wsOutput.GetLength() - 1);
3434   }
3435   return TRUE;
3436 }
FormatLCNumeric(CFX_LCNumeric & lcNum,const CFX_WideString & wsPattern,CFX_WideString & wsOutput)3437 FX_BOOL CFX_FormatString::FormatLCNumeric(CFX_LCNumeric& lcNum,
3438                                           const CFX_WideString& wsPattern,
3439                                           CFX_WideString& wsOutput) {
3440   int32_t dot_index_f = -1;
3441   FX_DWORD dwNumStyle = 0;
3442   CFX_WideString wsNumFormat;
3443   IFX_Locale* pLocale =
3444       GetNumericFormat(wsPattern, dot_index_f, dwNumStyle, wsNumFormat);
3445   if (!pLocale || wsNumFormat.IsEmpty()) {
3446     return FALSE;
3447   }
3448   int32_t cc = 0, ccf = 0;
3449   const FX_WCHAR* strf = (const FX_WCHAR*)wsNumFormat;
3450   int lenf = wsNumFormat.GetLength();
3451   double dbOrgRaw = lcNum.GetDouble();
3452   double dbRetValue = dbOrgRaw;
3453   if (dwNumStyle & FX_NUMSTYLE_Percent) {
3454     dbRetValue *= 100;
3455   }
3456   int32_t exponent = 0;
3457   if (dwNumStyle & FX_NUMSTYLE_Exponent) {
3458     int fixed_count = 0;
3459     while (ccf < dot_index_f) {
3460       switch (strf[ccf]) {
3461         case '\'':
3462           FX_GetLiteralText(strf, ccf, dot_index_f);
3463           break;
3464         case '9':
3465         case 'z':
3466         case 'Z':
3467           fixed_count++;
3468           break;
3469       }
3470       ccf++;
3471     }
3472     int threshold = 1;
3473     while (fixed_count > 1) {
3474       threshold *= 10;
3475       fixed_count--;
3476     }
3477     if (dbRetValue != 0) {
3478       if (dbRetValue < threshold) {
3479         dbRetValue *= 10;
3480         exponent = -1;
3481         while (dbRetValue < threshold) {
3482           dbRetValue *= 10;
3483           exponent -= 1;
3484         }
3485       } else if (dbRetValue > threshold) {
3486         threshold *= 10;
3487         while (dbRetValue > threshold) {
3488           dbRetValue /= 10;
3489           exponent += 1;
3490         }
3491       }
3492     }
3493   }
3494   if (dwNumStyle & (FX_NUMSTYLE_Percent | FX_NUMSTYLE_Exponent)) {
3495     lcNum = CFX_LCNumeric(dbRetValue);
3496   }
3497   FX_BOOL bTrimTailZeros = FALSE;
3498   int32_t iTreading =
3499       FX_GetNumTrailingLimit(wsNumFormat, dot_index_f, bTrimTailZeros);
3500   CFX_WideString wsNumeric = lcNum.ToString(iTreading, bTrimTailZeros);
3501   if (wsNumeric.IsEmpty()) {
3502     return FALSE;
3503   }
3504   CFX_WideString wsGroupSymbol;
3505   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping, wsGroupSymbol);
3506   FX_BOOL bNeg = FALSE;
3507   if (wsNumeric[0] == '-') {
3508     bNeg = TRUE;
3509     wsNumeric.Delete(0, 1);
3510   }
3511   FX_BOOL bAddNeg = FALSE;
3512   const FX_WCHAR* str = (const FX_WCHAR*)wsNumeric;
3513   int len = wsNumeric.GetLength();
3514   int dot_index = wsNumeric.Find('.');
3515   if (dot_index == -1) {
3516     dot_index = len;
3517   }
3518   ccf = dot_index_f - 1;
3519   cc = dot_index - 1;
3520   while (ccf >= 0) {
3521     switch (strf[ccf]) {
3522       case '9':
3523         if (cc >= 0) {
3524           wsOutput = CFX_WideStringC(str[cc]) + wsOutput;
3525           cc--;
3526         } else {
3527           wsOutput = CFX_WideStringC(L'0') + wsOutput;
3528         }
3529         ccf--;
3530         break;
3531       case 'z':
3532         if (cc >= 0) {
3533           if (lcNum.m_Integral != 0) {
3534             wsOutput = CFX_WideStringC(str[cc]) + wsOutput;
3535           }
3536           cc--;
3537         }
3538         ccf--;
3539         break;
3540       case 'Z':
3541         if (cc >= 0) {
3542           if (lcNum.m_Integral == 0) {
3543             wsOutput = CFX_WideStringC(L' ') + wsOutput;
3544           } else {
3545             wsOutput = CFX_WideStringC(str[cc]) + wsOutput;
3546           }
3547           cc--;
3548         } else {
3549           wsOutput = CFX_WideStringC(L' ') + wsOutput;
3550         }
3551         ccf--;
3552         break;
3553       case 'S':
3554         if (bNeg) {
3555           CFX_WideString wsMinusSymbol;
3556           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusSymbol);
3557           wsOutput = wsMinusSymbol + wsOutput;
3558           bAddNeg = TRUE;
3559         } else {
3560           wsOutput = CFX_WideStringC(L' ') + wsOutput;
3561         }
3562         ccf--;
3563         break;
3564       case 's':
3565         if (bNeg) {
3566           CFX_WideString wsMinusSymbol;
3567           pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusSymbol);
3568           wsOutput = wsMinusSymbol + wsOutput;
3569           bAddNeg = TRUE;
3570         }
3571         ccf--;
3572         break;
3573       case 'E': {
3574         CFX_WideString wsExp;
3575         wsExp.Format(L"E%+d", exponent);
3576         wsOutput = wsExp + wsOutput;
3577       }
3578         ccf--;
3579         break;
3580       case '$': {
3581         CFX_WideString wsSymbol;
3582         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);
3583         wsOutput = wsSymbol + wsOutput;
3584       }
3585         ccf--;
3586         break;
3587       case 'r':
3588         if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {
3589           if (bNeg) {
3590             wsOutput = L"CR" + wsOutput;
3591           }
3592           ccf -= 2;
3593           bAddNeg = TRUE;
3594         }
3595         break;
3596       case 'R':
3597         if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {
3598           if (bNeg) {
3599             wsOutput = L"CR" + wsOutput;
3600           } else {
3601             wsOutput = L"  " + wsOutput;
3602           }
3603           ccf -= 2;
3604           bAddNeg = TRUE;
3605         }
3606         break;
3607       case 'b':
3608         if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {
3609           if (bNeg) {
3610             wsOutput = L"db" + wsOutput;
3611           }
3612           ccf -= 2;
3613           bAddNeg = TRUE;
3614         }
3615         break;
3616       case 'B':
3617         if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {
3618           if (bNeg) {
3619             wsOutput = L"DB" + wsOutput;
3620           } else {
3621             wsOutput = L"  " + wsOutput;
3622           }
3623           ccf -= 2;
3624           bAddNeg = TRUE;
3625         }
3626         break;
3627       case '%': {
3628         CFX_WideString wsSymbol;
3629         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
3630         wsOutput = wsSymbol + wsOutput;
3631       }
3632         ccf--;
3633         break;
3634       case ',':
3635         if (cc >= 0) {
3636           wsOutput = wsGroupSymbol + wsOutput;
3637         }
3638         ccf--;
3639         break;
3640       case '(':
3641         if (bNeg) {
3642           wsOutput = L"(" + wsOutput;
3643         } else {
3644           wsOutput = L" " + wsOutput;
3645         }
3646         bAddNeg = TRUE;
3647         ccf--;
3648         break;
3649       case ')':
3650         if (bNeg) {
3651           wsOutput = L")" + wsOutput;
3652         } else {
3653           wsOutput = L" " + wsOutput;
3654         }
3655         ccf--;
3656         break;
3657       case '\'':
3658         wsOutput = FX_GetLiteralTextReverse(strf, ccf) + wsOutput;
3659         ccf--;
3660         break;
3661       default:
3662         wsOutput = CFX_WideStringC(strf[ccf]) + wsOutput;
3663         ccf--;
3664     }
3665   }
3666   if (cc >= 0) {
3667     int nPos = dot_index % 3;
3668     wsOutput.Empty();
3669     for (int32_t i = 0; i < dot_index; i++) {
3670       if (i % 3 == nPos && i != 0) {
3671         wsOutput += wsGroupSymbol;
3672       }
3673       wsOutput += wsNumeric[i];
3674     }
3675     if (dot_index < len) {
3676       CFX_WideString wsSymbol;
3677       pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsSymbol);
3678       wsOutput += wsSymbol;
3679       wsOutput += wsNumeric.Right(len - dot_index - 1);
3680     }
3681     if (bNeg) {
3682       CFX_WideString wsMinusymbol;
3683       pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusymbol);
3684       wsOutput = wsMinusymbol + wsOutput;
3685     }
3686     return FALSE;
3687   }
3688   if (dot_index_f == wsNumFormat.GetLength()) {
3689     if (!bAddNeg && bNeg) {
3690       CFX_WideString wsMinusymbol;
3691       pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusymbol);
3692       wsOutput = wsMinusymbol + wsOutput;
3693     }
3694     return TRUE;
3695   }
3696   CFX_WideString wsDotSymbol;
3697   pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsDotSymbol);
3698   if (strf[dot_index_f] == 'V') {
3699     wsOutput += wsDotSymbol;
3700   } else if (strf[dot_index_f] == '.') {
3701     if (dot_index < len) {
3702       wsOutput += wsDotSymbol;
3703     } else {
3704       if (strf[dot_index_f + 1] == '9' || strf[dot_index_f + 1] == 'Z') {
3705         wsOutput += wsDotSymbol;
3706       }
3707     }
3708   }
3709   ccf = dot_index_f + 1;
3710   cc = dot_index + 1;
3711   while (ccf < lenf) {
3712     switch (strf[ccf]) {
3713       case '\'':
3714         wsOutput += FX_GetLiteralText(strf, ccf, lenf);
3715         ccf++;
3716         break;
3717       case '9':
3718         if (cc < len) {
3719           wsOutput += str[cc];
3720           cc++;
3721         } else {
3722           wsOutput += L'0';
3723         }
3724         ccf++;
3725         break;
3726       case 'z':
3727         if (cc < len) {
3728           wsOutput += str[cc];
3729           cc++;
3730         }
3731         ccf++;
3732         break;
3733       case 'Z':
3734         if (cc < len) {
3735           wsOutput += str[cc];
3736           cc++;
3737         } else {
3738           wsOutput += L'0';
3739         }
3740         ccf++;
3741         break;
3742       case 'E': {
3743         CFX_WideString wsExp;
3744         wsExp.Format(L"E%+d", exponent);
3745         wsOutput += wsExp;
3746       }
3747         ccf++;
3748         break;
3749       case '$': {
3750         CFX_WideString wsSymbol;
3751         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol, wsSymbol);
3752         wsOutput += wsSymbol;
3753       }
3754         ccf++;
3755         break;
3756       case 'c':
3757         if (ccf + 1 < lenf && strf[ccf + 1] == 'r') {
3758           if (bNeg) {
3759             wsOutput += L"CR";
3760           }
3761           ccf += 2;
3762           bAddNeg = TRUE;
3763         }
3764         break;
3765       case 'C':
3766         if (ccf + 1 < lenf && strf[ccf + 1] == 'R') {
3767           if (bNeg) {
3768             wsOutput += L"CR";
3769           } else {
3770             wsOutput += L"  ";
3771           }
3772           ccf += 2;
3773           bAddNeg = TRUE;
3774         }
3775         break;
3776       case 'd':
3777         if (ccf + 1 < lenf && strf[ccf + 1] == 'b') {
3778           if (bNeg) {
3779             wsOutput += L"db";
3780           }
3781           ccf += 2;
3782           bAddNeg = TRUE;
3783         }
3784         break;
3785       case 'D':
3786         if (ccf + 1 < lenf && strf[ccf + 1] == 'B') {
3787           if (bNeg) {
3788             wsOutput += L"DB";
3789           } else {
3790             wsOutput += L"  ";
3791           }
3792           ccf += 2;
3793           bAddNeg = TRUE;
3794         }
3795         break;
3796       case '%': {
3797         CFX_WideString wsSymbol;
3798         pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent, wsSymbol);
3799         wsOutput += wsSymbol;
3800       }
3801         ccf++;
3802         break;
3803       case '8': {
3804         while (ccf < lenf && strf[ccf] == '8') {
3805           ccf++;
3806         }
3807         while (cc < len && FX_IsDigit(str[cc])) {
3808           wsOutput += str[cc];
3809           cc++;
3810         }
3811       } break;
3812       case ',':
3813         wsOutput += wsGroupSymbol;
3814         ccf++;
3815         break;
3816       case '(':
3817         if (bNeg) {
3818           wsOutput += '(';
3819         } else {
3820           wsOutput += ' ';
3821         }
3822         bAddNeg = TRUE;
3823         ccf++;
3824         break;
3825       case ')':
3826         if (bNeg) {
3827           wsOutput += ')';
3828         } else {
3829           wsOutput += ' ';
3830         }
3831         ccf++;
3832         break;
3833       default:
3834         ccf++;
3835     }
3836   }
3837   if (!bAddNeg && bNeg) {
3838     CFX_WideString wsMinusymbol;
3839     pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus, wsMinusymbol);
3840     wsOutput =
3841         wsOutput[0] + wsMinusymbol + wsOutput.Mid(1, wsOutput.GetLength() - 1);
3842   }
3843   return TRUE;
3844 }
FormatNum(const CFX_WideString & wsSrcNum,const CFX_WideString & wsPattern,CFX_WideString & wsOutput)3845 FX_BOOL CFX_FormatString::FormatNum(const CFX_WideString& wsSrcNum,
3846                                     const CFX_WideString& wsPattern,
3847                                     CFX_WideString& wsOutput) {
3848   if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty()) {
3849     return FALSE;
3850   }
3851   return FormatStrNum(wsSrcNum, wsPattern, wsOutput);
3852 }
FormatNum(FX_FLOAT fNum,const CFX_WideString & wsPattern,CFX_WideString & wsOutput)3853 FX_BOOL CFX_FormatString::FormatNum(FX_FLOAT fNum,
3854                                     const CFX_WideString& wsPattern,
3855                                     CFX_WideString& wsOutput) {
3856   if (wsPattern.IsEmpty()) {
3857     return FALSE;
3858   }
3859   CFX_LCNumeric lcNum(fNum);
3860   return FormatLCNumeric(lcNum, wsPattern, wsOutput);
3861 }
FX_DateFromCanonical(const CFX_WideString & wsDate,CFX_Unitime & datetime)3862 FX_BOOL FX_DateFromCanonical(const CFX_WideString& wsDate,
3863                              CFX_Unitime& datetime) {
3864   int32_t year = 1900;
3865   int32_t month = 1;
3866   int32_t day = 1;
3867   FX_WORD wYear = 0;
3868   int cc_start = 0, cc = 0;
3869   const FX_WCHAR* str = (const FX_WCHAR*)wsDate;
3870   int len = wsDate.GetLength();
3871   if (len > 10) {
3872     return FALSE;
3873   }
3874   while (cc < len && cc < 4) {
3875     if (!FX_IsDigit(str[cc])) {
3876       return FALSE;
3877     }
3878     wYear = wYear * 10 + str[cc++] - '0';
3879   }
3880   year = wYear;
3881   if (cc < 4 || wYear < 1900) {
3882     return FALSE;
3883   }
3884   if (cc < len) {
3885     if (str[cc] == '-') {
3886       cc++;
3887     }
3888     cc_start = cc;
3889     uint8_t tmpM = 0;
3890     while (cc < len && cc < cc_start + 2) {
3891       if (!FX_IsDigit(str[cc])) {
3892         return FALSE;
3893       }
3894       tmpM = tmpM * 10 + str[cc++] - '0';
3895     }
3896     month = tmpM;
3897     if (cc == cc_start + 1 || tmpM > 12 || tmpM < 1) {
3898       return FALSE;
3899     }
3900     if (cc < len) {
3901       if (str[cc] == '-') {
3902         cc++;
3903       }
3904       uint8_t tmpD = 0;
3905       cc_start = cc;
3906       while (cc < len && cc < cc_start + 2) {
3907         if (!FX_IsDigit(str[cc])) {
3908           return FALSE;
3909         }
3910         tmpD = tmpD * 10 + str[cc++] - '0';
3911       }
3912       day = tmpD;
3913       if (tmpD < 1) {
3914         return FALSE;
3915       }
3916       if ((tmpM == 1 || tmpM == 3 || tmpM == 5 || tmpM == 7 || tmpM == 8 ||
3917            tmpM == 10 || tmpM == 12) &&
3918           tmpD > 31) {
3919         return FALSE;
3920       }
3921       if ((tmpM == 4 || tmpM == 6 || tmpM == 9 || tmpM == 11) && tmpD > 30) {
3922         return FALSE;
3923       }
3924       FX_BOOL iLeapYear;
3925       if ((wYear % 4 == 0 && wYear % 100 != 0) || wYear % 400 == 0) {
3926         iLeapYear = TRUE;
3927       } else {
3928         iLeapYear = FALSE;
3929       }
3930       if ((iLeapYear && tmpM == 2 && tmpD > 29) ||
3931           (!iLeapYear && tmpM == 2 && tmpD > 28)) {
3932         return FALSE;
3933       }
3934     }
3935   }
3936   CFX_Unitime ut;
3937   ut.Set(year, month, day);
3938   datetime = datetime + ut;
3939   return TRUE;
3940 }
FX_TimeFromCanonical(const CFX_WideStringC & wsTime,CFX_Unitime & datetime,IFX_Locale * pLocale)3941 FX_BOOL FX_TimeFromCanonical(const CFX_WideStringC& wsTime,
3942                              CFX_Unitime& datetime,
3943                              IFX_Locale* pLocale) {
3944   if (wsTime.GetLength() == 0) {
3945     return FALSE;
3946   }
3947   uint8_t hour = 0;
3948   uint8_t minute = 0;
3949   uint8_t second = 0;
3950   FX_WORD millisecond = 0;
3951   int cc_start = 0, cc = cc_start;
3952   const FX_WCHAR* str = (const FX_WCHAR*)wsTime.GetPtr();
3953   int len = wsTime.GetLength();
3954   while (cc < len && cc < 2) {
3955     if (!FX_IsDigit(str[cc])) {
3956       return FALSE;
3957     }
3958     hour = hour * 10 + str[cc++] - '0';
3959   }
3960   if (cc < 2 || hour >= 24) {
3961     return FALSE;
3962   }
3963   if (cc < len) {
3964     if (str[cc] == ':') {
3965       cc++;
3966     }
3967     cc_start = cc;
3968     while (cc < len && cc < cc_start + 2) {
3969       if (!FX_IsDigit(str[cc])) {
3970         return FALSE;
3971       }
3972       minute = minute * 10 + str[cc++] - '0';
3973     }
3974     if (cc == cc_start + 1 || minute >= 60) {
3975       return FALSE;
3976     }
3977     if (cc < len) {
3978       if (str[cc] == ':') {
3979         cc++;
3980       }
3981       cc_start = cc;
3982       while (cc < len && cc < cc_start + 2) {
3983         if (!FX_IsDigit(str[cc])) {
3984           return FALSE;
3985         }
3986         second = second * 10 + str[cc++] - '0';
3987       }
3988       if (cc == cc_start + 1 || second >= 60) {
3989         return FALSE;
3990       }
3991       if (cc < len) {
3992         if (str[cc] == '.') {
3993           cc++;
3994           cc_start = cc;
3995           while (cc < len && cc < cc_start + 3) {
3996             if (!FX_IsDigit(str[cc])) {
3997               return FALSE;
3998             }
3999             millisecond = millisecond * 10 + str[cc++] - '0';
4000           }
4001           if (cc < cc_start + 3 || millisecond >= 1000) {
4002             return FALSE;
4003           }
4004         }
4005         if (cc < len) {
4006           FX_TIMEZONE tzDiff;
4007           tzDiff.tzHour = 0;
4008           tzDiff.tzMinute = 0;
4009           if (str[cc] != 'Z') {
4010             cc += FX_ParseTimeZone(str + cc, len - cc, tzDiff);
4011           }
4012           FX_ResolveZone(hour, minute, tzDiff, pLocale);
4013         }
4014       }
4015     }
4016   }
4017   CFX_Unitime ut;
4018   ut.Set(0, 0, 0, hour, minute, second, millisecond);
4019   datetime = datetime + ut;
4020   return TRUE;
4021 }
FX_GetSolarMonthDays(FX_WORD year,FX_WORD month)4022 static FX_WORD FX_GetSolarMonthDays(FX_WORD year, FX_WORD month) {
4023   if (month % 2) {
4024     return 31;
4025   } else if (month == 2) {
4026     return FX_IsLeapYear(year) ? 29 : 28;
4027   }
4028   return 30;
4029 }
FX_GetWeekDay(FX_WORD year,FX_WORD month,FX_WORD day)4030 static FX_WORD FX_GetWeekDay(FX_WORD year, FX_WORD month, FX_WORD day) {
4031   FX_WORD g_month_day[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
4032   FX_WORD nDays =
4033       (year - 1) % 7 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
4034   nDays += g_month_day[month - 1] + day;
4035   if (FX_IsLeapYear(year) && month > 2) {
4036     nDays++;
4037   }
4038   return nDays % 7;
4039 }
FX_GetWeekOfMonth(FX_WORD year,FX_WORD month,FX_WORD day)4040 static FX_WORD FX_GetWeekOfMonth(FX_WORD year, FX_WORD month, FX_WORD day) {
4041   FX_WORD week_day = FX_GetWeekDay(year, month, 1);
4042   FX_WORD week_index = 0;
4043   week_index += day / 7;
4044   day = day % 7;
4045   if (week_day + day > 7) {
4046     week_index++;
4047   }
4048   return week_index;
4049 }
FX_GetWeekOfYear(FX_WORD year,FX_WORD month,FX_WORD day)4050 static FX_WORD FX_GetWeekOfYear(FX_WORD year, FX_WORD month, FX_WORD day) {
4051   FX_WORD nDays = 0;
4052   for (FX_WORD i = 1; i < month; i++) {
4053     nDays += FX_GetSolarMonthDays(year, i);
4054   }
4055   nDays += day;
4056   FX_WORD week_day = FX_GetWeekDay(year, 1, 1);
4057   FX_WORD week_index = 1;
4058   week_index += nDays / 7;
4059   nDays = nDays % 7;
4060   if (week_day + nDays > 7) {
4061     week_index++;
4062   }
4063   return week_index;
4064 }
FX_DateFormat(const CFX_WideString & wsDatePattern,IFX_Locale * pLocale,const CFX_Unitime & datetime,CFX_WideString & wsResult)4065 static FX_BOOL FX_DateFormat(const CFX_WideString& wsDatePattern,
4066                              IFX_Locale* pLocale,
4067                              const CFX_Unitime& datetime,
4068                              CFX_WideString& wsResult) {
4069   FX_BOOL bRet = TRUE;
4070   int32_t year = datetime.GetYear();
4071   uint8_t month = datetime.GetMonth();
4072   uint8_t day = datetime.GetDay();
4073   int32_t ccf = 0;
4074   const FX_WCHAR* strf = (const FX_WCHAR*)wsDatePattern;
4075   int32_t lenf = wsDatePattern.GetLength();
4076   while (ccf < lenf) {
4077     if (strf[ccf] == '\'') {
4078       wsResult += FX_GetLiteralText(strf, ccf, lenf);
4079       ccf++;
4080       continue;
4081     } else if (FX_Local_Find(gs_wsDateSymbols, strf[ccf]) < 0) {
4082       wsResult += strf[ccf++];
4083       continue;
4084     }
4085     FX_DWORD dwSymbolNum = 1;
4086     FX_DWORD dwSymbol = strf[ccf++];
4087     while (ccf < lenf && strf[ccf] == dwSymbol) {
4088       ccf++;
4089       dwSymbolNum++;
4090     }
4091     dwSymbol = (dwSymbol << 8) | (dwSymbolNum + '0');
4092     if (dwSymbol == FXBSTR_ID(0, 0, 'D', '1')) {
4093       CFX_WideString wsDay;
4094       wsDay.Format(L"%d", day);
4095       wsResult += wsDay;
4096     } else if (dwSymbol == FXBSTR_ID(0, 0, 'D', '2')) {
4097       CFX_WideString wsDay;
4098       wsDay.Format(L"%02d", day);
4099       wsResult += wsDay;
4100     } else if (dwSymbol == FXBSTR_ID(0, 0, 'J', '1')) {
4101       FX_WORD nDays = 0;
4102       for (int i = 1; i < month; i++) {
4103         nDays += FX_GetSolarMonthDays(year, i);
4104       }
4105       nDays += day;
4106       CFX_WideString wsDays;
4107       wsDays.Format(L"%d", nDays);
4108       wsResult += wsDays;
4109     } else if (dwSymbol == FXBSTR_ID(0, 0, 'J', '3')) {
4110       FX_WORD nDays = 0;
4111       for (int i = 1; i < month; i++) {
4112         nDays += FX_GetSolarMonthDays(year, i);
4113       }
4114       nDays += day;
4115       CFX_WideString wsDays;
4116       wsDays.Format(L"%03d", nDays);
4117       wsResult += wsDays;
4118     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '1')) {
4119       CFX_WideString wsMonth;
4120       wsMonth.Format(L"%d", month);
4121       wsResult += wsMonth;
4122     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '2')) {
4123       CFX_WideString wsMonth;
4124       wsMonth.Format(L"%02d", month);
4125       wsResult += wsMonth;
4126     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '3')) {
4127       CFX_WideString wsTemp;
4128       pLocale->GetMonthName(month - 1, wsTemp, TRUE);
4129       wsResult += wsTemp;
4130     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '4')) {
4131       CFX_WideString wsTemp;
4132       pLocale->GetMonthName(month - 1, wsTemp, FALSE);
4133       wsResult += wsTemp;
4134     } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '1')) {
4135       FX_WORD wWeekDay = FX_GetWeekDay(year, month, day);
4136       CFX_WideString wsWeekDay;
4137       wsWeekDay.Format(L"%d", wWeekDay + 1);
4138       wsResult += wsWeekDay;
4139     } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '3')) {
4140       FX_WORD wWeekDay = FX_GetWeekDay(year, month, day);
4141       CFX_WideString wsTemp;
4142       pLocale->GetDayName(wWeekDay, wsTemp, TRUE);
4143       wsResult += wsTemp;
4144     } else if (dwSymbol == FXBSTR_ID(0, 0, 'E', '4')) {
4145       FX_WORD wWeekDay = FX_GetWeekDay(year, month, day);
4146       if (pLocale) {
4147         CFX_WideString wsTemp;
4148         pLocale->GetDayName(wWeekDay, wsTemp, FALSE);
4149         wsResult += wsTemp;
4150       }
4151     } else if (dwSymbol == FXBSTR_ID(0, 0, 'e', '1')) {
4152       FX_WORD wWeekDay = FX_GetWeekDay(year, month, day);
4153       CFX_WideString wsWeekDay;
4154       wsWeekDay.Format(L"%d", wWeekDay ? wWeekDay : 7);
4155       wsResult += wsWeekDay;
4156     } else if (dwSymbol == FXBSTR_ID(0, 0, 'G', '1')) {
4157       CFX_WideString wsTemp;
4158       pLocale->GetEraName(wsTemp, year < 0);
4159       wsResult += wsTemp;
4160     } else if (dwSymbol == FXBSTR_ID(0, 0, 'Y', '2')) {
4161       CFX_WideString wsYear;
4162       wsYear.Format(L"%02d", year % 100);
4163       wsResult += wsYear;
4164     } else if (dwSymbol == FXBSTR_ID(0, 0, 'Y', '4')) {
4165       CFX_WideString wsYear;
4166       wsYear.Format(L"%d", year);
4167       wsResult += wsYear;
4168     } else if (dwSymbol == FXBSTR_ID(0, 0, 'w', '1')) {
4169       FX_WORD week_index = FX_GetWeekOfMonth(year, month, day);
4170       CFX_WideString wsWeekInMonth;
4171       wsWeekInMonth.Format(L"%d", week_index);
4172       wsResult += wsWeekInMonth;
4173     } else if (dwSymbol == FXBSTR_ID(0, 0, 'W', '2')) {
4174       FX_WORD week_index = FX_GetWeekOfYear(year, month, day);
4175       CFX_WideString wsWeekInYear;
4176       wsWeekInYear.Format(L"%02d", week_index);
4177       wsResult += wsWeekInYear;
4178     }
4179   }
4180   return bRet;
4181 }
FX_TimeFormat(const CFX_WideString & wsTimePattern,IFX_Locale * pLocale,const CFX_Unitime & datetime,CFX_WideString & wsResult)4182 static FX_BOOL FX_TimeFormat(const CFX_WideString& wsTimePattern,
4183                              IFX_Locale* pLocale,
4184                              const CFX_Unitime& datetime,
4185                              CFX_WideString& wsResult) {
4186   FX_BOOL bGMT = FALSE;
4187   FX_BOOL bRet = TRUE;
4188   uint8_t hour = datetime.GetHour();
4189   uint8_t minute = datetime.GetMinute();
4190   uint8_t second = datetime.GetSecond();
4191   FX_WORD millisecond = datetime.GetMillisecond();
4192   int32_t ccf = 0;
4193   const FX_WCHAR* strf = (const FX_WCHAR*)wsTimePattern;
4194   int32_t lenf = wsTimePattern.GetLength();
4195   FX_WORD wHour = hour;
4196   FX_BOOL bPM = FALSE;
4197   if (wsTimePattern.Find('A') != -1) {
4198     if (wHour >= 12) {
4199       bPM = TRUE;
4200     }
4201   }
4202   while (ccf < lenf) {
4203     if (strf[ccf] == '\'') {
4204       wsResult += FX_GetLiteralText(strf, ccf, lenf);
4205       ccf++;
4206       continue;
4207     } else if (FX_Local_Find(gs_wsTimeSymbols, strf[ccf]) < 0) {
4208       wsResult += strf[ccf++];
4209       continue;
4210     }
4211     FX_DWORD dwSymbolNum = 1;
4212     FX_DWORD dwSymbol = strf[ccf++];
4213     while (ccf < lenf && strf[ccf] == dwSymbol) {
4214       ccf++;
4215       dwSymbolNum++;
4216     }
4217     dwSymbol = (dwSymbol << 8) | (dwSymbolNum + '0');
4218     if (dwSymbol == FXBSTR_ID(0, 0, 'h', '1')) {
4219       if (wHour > 12) {
4220         wHour -= 12;
4221       }
4222       CFX_WideString wsHour;
4223       wsHour.Format(L"%d", wHour == 0 ? 12 : wHour);
4224       wsResult += wsHour;
4225     } else if (dwSymbol == FXBSTR_ID(0, 0, 'h', '2')) {
4226       if (wHour > 12) {
4227         wHour -= 12;
4228       }
4229       CFX_WideString wsHour;
4230       wsHour.Format(L"%02d", wHour == 0 ? 12 : wHour);
4231       wsResult += wsHour;
4232     } else if (dwSymbol == FXBSTR_ID(0, 0, 'K', '1')) {
4233       CFX_WideString wsHour;
4234       wsHour.Format(L"%d", wHour == 0 ? 24 : wHour);
4235       wsResult += wsHour;
4236     } else if (dwSymbol == FXBSTR_ID(0, 0, 'K', '2')) {
4237       CFX_WideString wsHour;
4238       wsHour.Format(L"%02d", wHour == 0 ? 24 : wHour);
4239       wsResult += wsHour;
4240     } else if (dwSymbol == FXBSTR_ID(0, 0, 'k', '1')) {
4241       if (wHour > 12) {
4242         wHour -= 12;
4243       }
4244       CFX_WideString wsHour;
4245       wsHour.Format(L"%d", wHour);
4246       wsResult += wsHour;
4247     } else if (dwSymbol == FXBSTR_ID(0, 0, 'H', '1')) {
4248       CFX_WideString wsHour;
4249       wsHour.Format(L"%d", wHour);
4250       wsResult += wsHour;
4251     } else if (dwSymbol == FXBSTR_ID(0, 0, 'k', '2')) {
4252       if (wHour > 12) {
4253         wHour -= 12;
4254       }
4255       CFX_WideString wsHour;
4256       wsHour.Format(L"%02d", wHour);
4257       wsResult += wsHour;
4258     } else if (dwSymbol == FXBSTR_ID(0, 0, 'H', '2')) {
4259       CFX_WideString wsHour;
4260       wsHour.Format(L"%02d", wHour);
4261       wsResult += wsHour;
4262     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '1')) {
4263       CFX_WideString wsMinute;
4264       wsMinute.Format(L"%d", minute);
4265       wsResult += wsMinute;
4266     } else if (dwSymbol == FXBSTR_ID(0, 0, 'M', '2')) {
4267       CFX_WideString wsMinute;
4268       wsMinute.Format(L"%02d", minute);
4269       wsResult += wsMinute;
4270     } else if (dwSymbol == FXBSTR_ID(0, 0, 'S', '1')) {
4271       CFX_WideString wsSecond;
4272       wsSecond.Format(L"%d", second);
4273       wsResult += wsSecond;
4274     } else if (dwSymbol == FXBSTR_ID(0, 0, 'S', '2')) {
4275       CFX_WideString wsSecond;
4276       wsSecond.Format(L"%02d", second);
4277       wsResult += wsSecond;
4278     } else if (dwSymbol == FXBSTR_ID(0, 0, 'F', '3')) {
4279       CFX_WideString wsMilliseconds;
4280       wsMilliseconds.Format(L"%03d", millisecond);
4281       wsResult += wsMilliseconds;
4282     } else if (dwSymbol == FXBSTR_ID(0, 0, 'A', '1')) {
4283       CFX_WideString wsMeridiem;
4284       pLocale->GetMeridiemName(wsMeridiem, !bPM);
4285       wsResult += wsMeridiem;
4286     } else if (dwSymbol == FXBSTR_ID(0, 0, 'Z', '1')) {
4287       wsResult += FX_WSTRC(L"GMT");
4288       FX_TIMEZONE tz;
4289       pLocale->GetTimeZone(tz);
4290       if (!bGMT && (tz.tzHour != 0 || tz.tzMinute != 0)) {
4291         if (tz.tzHour < 0) {
4292           wsResult += FX_WSTRC(L"-");
4293         } else {
4294           wsResult += FX_WSTRC(L"+");
4295         }
4296         CFX_WideString wsTimezone;
4297         wsTimezone.Format(L"%02d:%02d", FXSYS_abs(tz.tzHour), tz.tzMinute);
4298         wsResult += wsTimezone;
4299       }
4300     } else if (dwSymbol == FXBSTR_ID(0, 0, 'z', '1')) {
4301       FX_TIMEZONE tz;
4302       pLocale->GetTimeZone(tz);
4303       if (!bGMT && tz.tzHour != 0 && tz.tzMinute != 0) {
4304         if (tz.tzHour < 0) {
4305           wsResult += FX_WSTRC(L"-");
4306         } else {
4307           wsResult += FX_WSTRC(L"+");
4308         }
4309         CFX_WideString wsTimezone;
4310         wsTimezone.Format(L"%02d:%02d", FXSYS_abs(tz.tzHour), tz.tzMinute);
4311         wsResult += wsTimezone;
4312       }
4313     }
4314   }
4315   return bRet;
4316 }
FX_FormatDateTime(const CFX_Unitime & dt,const CFX_WideString & wsDatePattern,const CFX_WideString & wsTimePattern,FX_BOOL bDateFirst,IFX_Locale * pLocale,CFX_WideString & wsOutput)4317 static FX_BOOL FX_FormatDateTime(const CFX_Unitime& dt,
4318                                  const CFX_WideString& wsDatePattern,
4319                                  const CFX_WideString& wsTimePattern,
4320                                  FX_BOOL bDateFirst,
4321                                  IFX_Locale* pLocale,
4322                                  CFX_WideString& wsOutput) {
4323   FX_BOOL bRet = TRUE;
4324   CFX_WideString wsDateOut, wsTimeOut;
4325   if (!wsDatePattern.IsEmpty()) {
4326     bRet &= FX_DateFormat(wsDatePattern, pLocale, dt, wsDateOut);
4327   }
4328   if (!wsTimePattern.IsEmpty()) {
4329     bRet &= FX_TimeFormat(wsTimePattern, pLocale, dt, wsTimeOut);
4330   }
4331   wsOutput = bDateFirst ? wsDateOut + wsTimeOut : wsTimeOut + wsDateOut;
4332   return bRet;
4333 }
FormatDateTime(const CFX_WideString & wsSrcDateTime,const CFX_WideString & wsPattern,CFX_WideString & wsOutput)4334 FX_BOOL CFX_FormatString::FormatDateTime(const CFX_WideString& wsSrcDateTime,
4335                                          const CFX_WideString& wsPattern,
4336                                          CFX_WideString& wsOutput) {
4337   if (wsSrcDateTime.IsEmpty() || wsPattern.IsEmpty()) {
4338     return FALSE;
4339   }
4340   CFX_WideString wsDatePattern, wsTimePattern;
4341   IFX_Locale* pLocale = NULL;
4342   FX_DATETIMETYPE eCategory =
4343       GetDateTimeFormat(wsPattern, pLocale, wsDatePattern, wsTimePattern);
4344   if (pLocale == NULL || eCategory == FX_DATETIMETYPE_Unknown) {
4345     return FALSE;
4346   }
4347   CFX_Unitime dt(0);
4348   int32_t iT = wsSrcDateTime.Find(L"T");
4349   if (iT < 0) {
4350     if (eCategory == FX_DATETIMETYPE_Date) {
4351       FX_DateFromCanonical(wsSrcDateTime, dt);
4352     } else if (eCategory == FX_DATETIMETYPE_Time) {
4353       FX_TimeFromCanonical(wsSrcDateTime, dt, pLocale);
4354     }
4355   } else {
4356     FX_DateFromCanonical(wsSrcDateTime.Left(iT), dt);
4357     FX_TimeFromCanonical(
4358         wsSrcDateTime.Right(wsSrcDateTime.GetLength() - iT - 1), dt, pLocale);
4359   }
4360   return FX_FormatDateTime(dt, wsDatePattern, wsTimePattern,
4361                            eCategory != FX_DATETIMETYPE_TimeDate, pLocale,
4362                            wsOutput);
4363 }
FormatDateTime(const CFX_WideString & wsSrcDateTime,const CFX_WideString & wsPattern,CFX_WideString & wsOutput,FX_DATETIMETYPE eDateTimeType)4364 FX_BOOL CFX_FormatString::FormatDateTime(const CFX_WideString& wsSrcDateTime,
4365                                          const CFX_WideString& wsPattern,
4366                                          CFX_WideString& wsOutput,
4367                                          FX_DATETIMETYPE eDateTimeType) {
4368   if (wsSrcDateTime.IsEmpty() || wsPattern.IsEmpty()) {
4369     return FALSE;
4370   }
4371   CFX_WideString wsDatePattern, wsTimePattern;
4372   IFX_Locale* pLocale = NULL;
4373   FX_DATETIMETYPE eCategory =
4374       GetDateTimeFormat(wsPattern, pLocale, wsDatePattern, wsTimePattern);
4375   if (!pLocale) {
4376     return FALSE;
4377   }
4378   if (eCategory == FX_DATETIMETYPE_Unknown) {
4379     if (eDateTimeType == FX_DATETIMETYPE_Time) {
4380       wsTimePattern = wsDatePattern;
4381       wsDatePattern.Empty();
4382     }
4383     eCategory = eDateTimeType;
4384   }
4385   if (eCategory == FX_DATETIMETYPE_Unknown) {
4386     return FALSE;
4387   }
4388   CFX_Unitime dt(0);
4389   int32_t iT = wsSrcDateTime.Find(L"T");
4390   if (iT < 0) {
4391     if (eCategory == FX_DATETIMETYPE_Date &&
4392         FX_DateFromCanonical(wsSrcDateTime, dt)) {
4393       return FX_FormatDateTime(dt, wsDatePattern, wsTimePattern, TRUE, pLocale,
4394                                wsOutput);
4395     } else if (eCategory == FX_DATETIMETYPE_Time &&
4396                FX_TimeFromCanonical(wsSrcDateTime, dt, pLocale)) {
4397       return FX_FormatDateTime(dt, wsDatePattern, wsTimePattern, TRUE, pLocale,
4398                                wsOutput);
4399     }
4400   } else {
4401     CFX_WideStringC wsSrcDate((const FX_WCHAR*)wsSrcDateTime, iT);
4402     CFX_WideStringC wsSrcTime((const FX_WCHAR*)wsSrcDateTime + iT + 1,
4403                               wsSrcDateTime.GetLength() - iT - 1);
4404     if (wsSrcDate.IsEmpty() || wsSrcTime.IsEmpty()) {
4405       return FALSE;
4406     }
4407     if (FX_DateFromCanonical(wsSrcDate, dt) &&
4408         FX_TimeFromCanonical(wsSrcTime, dt, pLocale)) {
4409       return FX_FormatDateTime(dt, wsDatePattern, wsTimePattern,
4410                                eCategory != FX_DATETIMETYPE_TimeDate, pLocale,
4411                                wsOutput);
4412     }
4413   }
4414   return FALSE;
4415 }
FormatDateTime(const CFX_Unitime & dt,const CFX_WideString & wsPattern,CFX_WideString & wsOutput)4416 FX_BOOL CFX_FormatString::FormatDateTime(const CFX_Unitime& dt,
4417                                          const CFX_WideString& wsPattern,
4418                                          CFX_WideString& wsOutput) {
4419   if (wsPattern.IsEmpty()) {
4420     return FALSE;
4421   }
4422   CFX_WideString wsDatePattern, wsTimePattern;
4423   IFX_Locale* pLocale = NULL;
4424   FX_DATETIMETYPE eCategory =
4425       GetDateTimeFormat(wsPattern, pLocale, wsDatePattern, wsTimePattern);
4426   if (!pLocale) {
4427     return FALSE;
4428   }
4429   return FX_FormatDateTime(dt, wsPattern, wsTimePattern,
4430                            eCategory != FX_DATETIMETYPE_TimeDate, pLocale,
4431                            wsOutput);
4432 }
FormatZero(const CFX_WideString & wsPattern,CFX_WideString & wsOutput)4433 FX_BOOL CFX_FormatString::FormatZero(const CFX_WideString& wsPattern,
4434                                      CFX_WideString& wsOutput) {
4435   if (wsPattern.IsEmpty()) {
4436     return FALSE;
4437   }
4438   CFX_WideString wsTextFormat;
4439   GetTextFormat(wsPattern, FX_WSTRC(L"zero"), wsTextFormat);
4440   int32_t iPattern = 0;
4441   const FX_WCHAR* pStrPattern = (const FX_WCHAR*)wsTextFormat;
4442   int32_t iLenPattern = wsTextFormat.GetLength();
4443   while (iPattern < iLenPattern) {
4444     if (pStrPattern[iPattern] == '\'') {
4445       wsOutput += FX_GetLiteralText(pStrPattern, iPattern, iLenPattern);
4446       iPattern++;
4447       continue;
4448     } else {
4449       wsOutput += pStrPattern[iPattern++];
4450       continue;
4451     }
4452   }
4453   return TRUE;
4454 }
FormatNull(const CFX_WideString & wsPattern,CFX_WideString & wsOutput)4455 FX_BOOL CFX_FormatString::FormatNull(const CFX_WideString& wsPattern,
4456                                      CFX_WideString& wsOutput) {
4457   if (wsPattern.IsEmpty()) {
4458     return FALSE;
4459   }
4460   CFX_WideString wsTextFormat;
4461   GetTextFormat(wsPattern, FX_WSTRC(L"null"), wsTextFormat);
4462   int32_t iPattern = 0;
4463   const FX_WCHAR* pStrPattern = (const FX_WCHAR*)wsTextFormat;
4464   int32_t iLenPattern = wsTextFormat.GetLength();
4465   while (iPattern < iLenPattern) {
4466     if (pStrPattern[iPattern] == '\'') {
4467       wsOutput += FX_GetLiteralText(pStrPattern, iPattern, iLenPattern);
4468       iPattern++;
4469       continue;
4470     } else {
4471       wsOutput += pStrPattern[iPattern++];
4472       continue;
4473     }
4474   }
4475   return TRUE;
4476 }
GetPatternLocale(const CFX_WideStringC & wsLocale)4477 IFX_Locale* CFX_FormatString::GetPatternLocale(
4478     const CFX_WideStringC& wsLocale) {
4479   if (m_bUseLCID) {
4480   }
4481   return m_pLocaleMgr->GetLocaleByName(wsLocale);
4482 }
4483 #define FXMATH_DECIMAL_SCALELIMIT 0x1c
4484 #define FXMATH_DECIMAL_NEGMASK (0x80000000L)
4485 #define FXMATH_DECIMAL_FORCEBOOL(x) (!(!(x)))
4486 #define FXMATH_DECIMAL_MAKEFLAGS(NEG, SCALE) \
4487   (((SCALE) << 0x10) | ((NEG) ? FXMATH_DECIMAL_NEGMASK : 0))
4488 #define FXMATH_DECIMAL_FLAGS2NEG(FLAGS) \
4489   FXMATH_DECIMAL_FORCEBOOL((FLAGS)&FXMATH_DECIMAL_NEGMASK)
4490 #define FXMATH_DECIMAL_FLAGS2SCALE(FLAGS) \
4491   ((uint8_t)(((FLAGS) & ~FXMATH_DECIMAL_NEGMASK) >> 0x10))
4492 #define FXMATH_DECIMAL_RSHIFT32BIT(x) ((x) >> 0x10 >> 0x10)
4493 #define FXMATH_DECIMAL_LSHIFT32BIT(x) ((x) << 0x10 << 0x10)
fxmath_decimal_helper_div10(uint64_t & phi,uint64_t & pmid,uint64_t & plo)4494 static inline uint8_t fxmath_decimal_helper_div10(uint64_t& phi,
4495                                                   uint64_t& pmid,
4496                                                   uint64_t& plo) {
4497   uint8_t retVal;
4498   pmid += FXMATH_DECIMAL_LSHIFT32BIT(phi % 0xA);
4499   phi /= 0xA;
4500   plo += FXMATH_DECIMAL_LSHIFT32BIT(pmid % 0xA);
4501   pmid /= 0xA;
4502   retVal = plo % 0xA;
4503   plo /= 0xA;
4504   return retVal;
4505 }
fxmath_decimal_helper_div10_any(uint64_t nums[],uint8_t numcount)4506 static inline uint8_t fxmath_decimal_helper_div10_any(uint64_t nums[],
4507                                                       uint8_t numcount) {
4508   uint8_t retVal = 0;
4509   for (int i = numcount - 1; i > 0; i--) {
4510     nums[i - 1] += FXMATH_DECIMAL_LSHIFT32BIT(nums[i] % 0xA);
4511     nums[i] /= 0xA;
4512   }
4513   if (numcount) {
4514     retVal = nums[0] % 0xA;
4515     nums[0] /= 0xA;
4516   }
4517   return retVal;
4518 }
fxmath_decimal_helper_mul10(uint64_t & phi,uint64_t & pmid,uint64_t & plo)4519 static inline void fxmath_decimal_helper_mul10(uint64_t& phi,
4520                                                uint64_t& pmid,
4521                                                uint64_t& plo) {
4522   plo *= 0xA;
4523   pmid = pmid * 0xA + FXMATH_DECIMAL_RSHIFT32BIT(plo);
4524   plo = (uint32_t)plo;
4525   phi = phi * 0xA + FXMATH_DECIMAL_RSHIFT32BIT(pmid);
4526   pmid = (uint32_t)pmid;
4527 }
fxmath_decimal_helper_mul10_any(uint64_t nums[],uint8_t numcount)4528 static inline void fxmath_decimal_helper_mul10_any(uint64_t nums[],
4529                                                    uint8_t numcount) {
4530   nums[0] *= 0xA;
4531   for (int i = 1; i < numcount; i++) {
4532     nums[i] = nums[i] * 0xA + FXMATH_DECIMAL_RSHIFT32BIT(nums[i - 1]);
4533     nums[i - 1] = (uint32_t)nums[i - 1];
4534   }
4535 }
fxmath_decimal_helper_normalize(uint64_t & phi,uint64_t & pmid,uint64_t & plo)4536 static inline void fxmath_decimal_helper_normalize(uint64_t& phi,
4537                                                    uint64_t& pmid,
4538                                                    uint64_t& plo) {
4539   phi += FXMATH_DECIMAL_RSHIFT32BIT(pmid);
4540   pmid = (uint32_t)pmid;
4541   pmid += FXMATH_DECIMAL_RSHIFT32BIT(plo);
4542   plo = (uint32_t)plo;
4543   phi += FXMATH_DECIMAL_RSHIFT32BIT(pmid);
4544   pmid = (uint32_t)pmid;
4545 }
fxmath_decimal_helper_normalize_any(uint64_t nums[],uint8_t len)4546 static inline void fxmath_decimal_helper_normalize_any(uint64_t nums[],
4547                                                        uint8_t len) {
4548   {
4549     for (int i = len - 2; i > 0; i--) {
4550       nums[i + 1] += FXMATH_DECIMAL_RSHIFT32BIT(nums[i]);
4551       nums[i] = (uint32_t)nums[i];
4552     }
4553   }
4554   {
4555     for (int i = 0; i < len - 1; i++) {
4556       nums[i + 1] += FXMATH_DECIMAL_RSHIFT32BIT(nums[i]);
4557       nums[i] = (uint32_t)nums[i];
4558     }
4559   }
4560 }
fxmath_decimal_helper_raw_compare(uint32_t hi1,uint32_t mid1,uint32_t lo1,uint32_t hi2,uint32_t mid2,uint32_t lo2)4561 static inline int8_t fxmath_decimal_helper_raw_compare(uint32_t hi1,
4562                                                        uint32_t mid1,
4563                                                        uint32_t lo1,
4564                                                        uint32_t hi2,
4565                                                        uint32_t mid2,
4566                                                        uint32_t lo2) {
4567   int8_t retVal = 0;
4568   if (!retVal) {
4569     retVal += (hi1 > hi2 ? 1 : (hi1 < hi2 ? -1 : 0));
4570   }
4571   if (!retVal) {
4572     retVal += (mid1 > mid2 ? 1 : (mid1 < mid2 ? -1 : 0));
4573   }
4574   if (!retVal) {
4575     retVal += (lo1 > lo2 ? 1 : (lo1 < lo2 ? -1 : 0));
4576   }
4577   return retVal;
4578 }
fxmath_decimal_helper_raw_compare_any(uint64_t a[],uint8_t al,uint64_t b[],uint8_t bl)4579 static inline int8_t fxmath_decimal_helper_raw_compare_any(uint64_t a[],
4580                                                            uint8_t al,
4581                                                            uint64_t b[],
4582                                                            uint8_t bl) {
4583   int8_t retVal = 0;
4584   for (int i = std::max(al - 1, bl - 1); i >= 0; i--) {
4585     uint64_t l = (i >= al ? 0 : a[i]), r = (i >= bl ? 0 : b[i]);
4586     retVal += (l > r ? 1 : (l < r ? -1 : 0));
4587     if (retVal) {
4588       return retVal;
4589     }
4590   }
4591   return retVal;
4592 }
fxmath_decimal_helper_dec_any(uint64_t a[],uint8_t al)4593 static inline void fxmath_decimal_helper_dec_any(uint64_t a[], uint8_t al) {
4594   for (int i = 0; i < al; i++) {
4595     if (a[i]--) {
4596       return;
4597     }
4598   }
4599 }
fxmath_decimal_helper_inc_any(uint64_t a[],uint8_t al)4600 static inline void fxmath_decimal_helper_inc_any(uint64_t a[], uint8_t al) {
4601   for (int i = 0; i < al; i++) {
4602     a[i]++;
4603     if ((uint32_t)a[i] == a[i]) {
4604       return;
4605     }
4606     a[i] = 0;
4607   }
4608 }
fxmath_decimal_helper_raw_mul(uint64_t a[],uint8_t al,uint64_t b[],uint8_t bl,uint64_t c[],uint8_t cl)4609 static inline void fxmath_decimal_helper_raw_mul(uint64_t a[],
4610                                                  uint8_t al,
4611                                                  uint64_t b[],
4612                                                  uint8_t bl,
4613                                                  uint64_t c[],
4614                                                  uint8_t cl) {
4615   assert(al + bl <= cl);
4616   {
4617     for (int i = 0; i < cl; i++) {
4618       c[i] = 0;
4619     }
4620   }
4621   {
4622     for (int i = 0; i < al; i++) {
4623       for (int j = 0; j < bl; j++) {
4624         uint64_t m = (uint64_t)a[i] * b[j];
4625         c[i + j] += (uint32_t)m;
4626         c[i + j + 1] += FXMATH_DECIMAL_RSHIFT32BIT(m);
4627       }
4628     }
4629   }
4630   {
4631     for (int i = 0; i < cl - 1; i++) {
4632       c[i + 1] += FXMATH_DECIMAL_RSHIFT32BIT(c[i]);
4633       c[i] = (uint32_t)c[i];
4634     }
4635   }
4636   {
4637     for (int i = 0; i < cl; i++) {
4638       c[i] = (uint32_t)c[i];
4639     }
4640   }
4641 }
fxmath_decimal_helper_raw_div(uint64_t a[],uint8_t al,uint64_t b[],uint8_t bl,uint64_t c[],uint8_t cl)4642 static inline void fxmath_decimal_helper_raw_div(uint64_t a[],
4643                                                  uint8_t al,
4644                                                  uint64_t b[],
4645                                                  uint8_t bl,
4646                                                  uint64_t c[],
4647                                                  uint8_t cl) {
4648   int i;
4649   for (i = 0; i < cl; i++) {
4650     c[i] = 0;
4651   }
4652   uint64_t left[16] = {0}, right[16] = {0};
4653   left[0] = 0;
4654   for (i = 0; i < al; i++) {
4655     right[i] = a[i];
4656   }
4657   uint64_t tmp[16];
4658   while (fxmath_decimal_helper_raw_compare_any(left, al, right, al) <= 0) {
4659     uint64_t cur[16];
4660     for (i = 0; i < al; i++) {
4661       cur[i] = left[i] + right[i];
4662     }
4663     for (i = al - 1; i >= 0; i--) {
4664       if (i) {
4665         cur[i - 1] += FXMATH_DECIMAL_LSHIFT32BIT(cur[i] % 2);
4666       }
4667       cur[i] /= 2;
4668     }
4669     fxmath_decimal_helper_raw_mul(cur, al, b, bl, tmp, 16);
4670     switch (fxmath_decimal_helper_raw_compare_any(tmp, 16, a, al)) {
4671       case -1:
4672         for (i = 0; i < 16; i++) {
4673           left[i] = cur[i];
4674         }
4675         left[0]++;
4676         fxmath_decimal_helper_normalize_any(left, al);
4677         break;
4678       case 1:
4679         for (i = 0; i < 16; i++) {
4680           right[i] = cur[i];
4681         }
4682         fxmath_decimal_helper_dec_any(right, al);
4683         break;
4684       case 0:
4685         for (i = 0; i < std::min(al, cl); i++) {
4686           c[i] = cur[i];
4687         }
4688         return;
4689     }
4690   }
4691   for (i = 0; i < std::min(al, cl); i++) {
4692     c[i] = left[i];
4693   }
4694 }
fxmath_decimal_helper_outofrange(uint64_t a[],uint8_t al,uint8_t goal)4695 static inline FX_BOOL fxmath_decimal_helper_outofrange(uint64_t a[],
4696                                                        uint8_t al,
4697                                                        uint8_t goal) {
4698   for (int i = goal; i < al; i++) {
4699     if (a[i]) {
4700       return TRUE;
4701     }
4702   }
4703   return FALSE;
4704 }
fxmath_decimal_helper_shrinkintorange(uint64_t a[],uint8_t al,uint8_t goal,uint8_t & scale)4705 static inline void fxmath_decimal_helper_shrinkintorange(uint64_t a[],
4706                                                          uint8_t al,
4707                                                          uint8_t goal,
4708                                                          uint8_t& scale) {
4709   FX_BOOL bRoundUp = FALSE;
4710   while (scale != 0 && (scale > FXMATH_DECIMAL_SCALELIMIT ||
4711                         fxmath_decimal_helper_outofrange(a, al, goal))) {
4712     bRoundUp = fxmath_decimal_helper_div10_any(a, al) >= 5;
4713     scale--;
4714   }
4715   if (bRoundUp) {
4716     fxmath_decimal_helper_normalize_any(a, goal);
4717     fxmath_decimal_helper_inc_any(a, goal);
4718   }
4719 }
fxmath_decimal_helper_truncate(uint64_t & phi,uint64_t & pmid,uint64_t & plo,uint8_t & scale,uint8_t minscale=0)4720 static inline void fxmath_decimal_helper_truncate(uint64_t& phi,
4721                                                   uint64_t& pmid,
4722                                                   uint64_t& plo,
4723                                                   uint8_t& scale,
4724                                                   uint8_t minscale = 0) {
4725   while (scale > minscale) {
4726     uint64_t thi = phi, tmid = pmid, tlo = plo;
4727     if (fxmath_decimal_helper_div10(thi, tmid, tlo) != 0) {
4728       break;
4729     }
4730     phi = thi, pmid = tmid, plo = tlo;
4731     scale--;
4732   }
4733 }
CFX_Decimal()4734 CFX_Decimal::CFX_Decimal() {
4735   m_uLo = m_uMid = m_uHi = m_uFlags = 0;
4736 }
CFX_Decimal(uint64_t val)4737 CFX_Decimal::CFX_Decimal(uint64_t val) {
4738   m_uLo = (uint32_t)val;
4739   m_uMid = (uint32_t)FXMATH_DECIMAL_RSHIFT32BIT(val);
4740   m_uHi = 0;
4741   m_uFlags = 0;
4742 }
CFX_Decimal(uint32_t val)4743 CFX_Decimal::CFX_Decimal(uint32_t val) {
4744   m_uLo = (uint32_t)val;
4745   m_uMid = m_uHi = 0;
4746   m_uFlags = 0;
4747 }
CFX_Decimal(uint32_t lo,uint32_t mid,uint32_t hi,FX_BOOL neg,uint8_t scale)4748 CFX_Decimal::CFX_Decimal(uint32_t lo,
4749                          uint32_t mid,
4750                          uint32_t hi,
4751                          FX_BOOL neg,
4752                          uint8_t scale) {
4753   scale = (scale > FXMATH_DECIMAL_SCALELIMIT ? 0 : scale);
4754   m_uLo = lo;
4755   m_uMid = mid;
4756   m_uHi = hi;
4757   m_uFlags = FXMATH_DECIMAL_MAKEFLAGS(neg && IsNotZero(), scale);
4758 }
CFX_Decimal(int32_t val)4759 CFX_Decimal::CFX_Decimal(int32_t val) {
4760   if (val >= 0) {
4761     *this = CFX_Decimal((uint32_t)val);
4762   } else {
4763     *this = CFX_Decimal((uint32_t)-val);
4764     SetNegate();
4765   }
4766 }
CFX_Decimal(int64_t val)4767 CFX_Decimal::CFX_Decimal(int64_t val) {
4768   if (val >= 0) {
4769     *this = CFX_Decimal((uint64_t)val);
4770   } else {
4771     *this = CFX_Decimal((uint64_t)-val);
4772     SetNegate();
4773   }
4774 }
CFX_Decimal(FX_FLOAT val,uint8_t scale)4775 CFX_Decimal::CFX_Decimal(FX_FLOAT val, uint8_t scale) {
4776   FX_FLOAT newval = fabs(val);
4777   uint64_t phi, pmid, plo;
4778   plo = (uint64_t)newval;
4779   pmid = (uint64_t)(newval / 1e32);
4780   phi = (uint64_t)(newval / 1e64);
4781   newval = FXSYS_fmod(newval, 1.0f);
4782   for (uint8_t iter = 0; iter < scale; iter++) {
4783     fxmath_decimal_helper_mul10(phi, pmid, plo);
4784     newval *= 10;
4785     plo += (uint64_t)newval;
4786     newval = FXSYS_fmod(newval, 1.0f);
4787   }
4788   plo += FXSYS_round(newval);
4789   fxmath_decimal_helper_normalize(phi, pmid, plo);
4790   m_uHi = (uint32_t)phi;
4791   m_uMid = (uint32_t)pmid;
4792   m_uLo = (uint32_t)plo;
4793   m_uFlags = FXMATH_DECIMAL_MAKEFLAGS(val < 0 && IsNotZero(), scale);
4794 }
CFX_Decimal(const CFX_WideStringC & strObj)4795 CFX_Decimal::CFX_Decimal(const CFX_WideStringC& strObj) {
4796   const FX_WCHAR* str = strObj.GetPtr();
4797   const FX_WCHAR* strBound = str + strObj.GetLength();
4798   FX_BOOL pointmet = 0;
4799   FX_BOOL negmet = 0;
4800   uint8_t scale = 0;
4801   m_uHi = m_uMid = m_uLo = 0;
4802   while (str != strBound && *str == ' ') {
4803     str++;
4804   }
4805   if (str != strBound && *str == '-') {
4806     negmet = 1;
4807     str++;
4808   } else if (str != strBound && *str == '+') {
4809     str++;
4810   }
4811   while (str != strBound && ((*str >= '0' && *str <= '9') || *str == '.') &&
4812          scale < FXMATH_DECIMAL_SCALELIMIT) {
4813     if (*str == '.') {
4814       if (pointmet) {
4815         goto cont;
4816       }
4817       pointmet = 1;
4818     } else {
4819       m_uHi = m_uHi * 0xA + FXMATH_DECIMAL_RSHIFT32BIT((uint64_t)m_uMid * 0xA);
4820       m_uMid = m_uMid * 0xA + FXMATH_DECIMAL_RSHIFT32BIT((uint64_t)m_uLo * 0xA);
4821       m_uLo = m_uLo * 0xA + (*str - '0');
4822       if (pointmet) {
4823         scale++;
4824       }
4825     }
4826   cont:
4827     str++;
4828   }
4829   m_uFlags = FXMATH_DECIMAL_MAKEFLAGS(negmet && IsNotZero(), scale);
4830 }
CFX_Decimal(const CFX_ByteStringC & strObj)4831 CFX_Decimal::CFX_Decimal(const CFX_ByteStringC& strObj) {
4832   CFX_WideString wstrObj;
4833   wstrObj.ConvertFrom(strObj);
4834   *this = CFX_Decimal(wstrObj);
4835 }
operator CFX_WideString() const4836 CFX_Decimal::operator CFX_WideString() const {
4837   CFX_WideString retString;
4838   CFX_WideString tmpbuf;
4839   uint64_t phi = m_uHi, pmid = m_uMid, plo = m_uLo;
4840   while (phi || pmid || plo) {
4841     tmpbuf += fxmath_decimal_helper_div10(phi, pmid, plo) + '0';
4842   }
4843   uint8_t outputlen = (uint8_t)tmpbuf.GetLength();
4844   uint8_t scale = (uint8_t)FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags);
4845   while (scale >= outputlen) {
4846     tmpbuf += '0';
4847     outputlen++;
4848   }
4849   if (FXMATH_DECIMAL_FLAGS2NEG(m_uFlags) && IsNotZero()) {
4850     retString += '-';
4851   }
4852   for (uint8_t idx = 0; idx < outputlen; idx++) {
4853     if (idx == (outputlen - scale) && scale != 0) {
4854       retString += '.';
4855     }
4856     retString += tmpbuf[outputlen - 1 - idx];
4857   }
4858   return retString;
4859 }
operator double() const4860 CFX_Decimal::operator double() const {
4861   double pow = (double)(1 << 16) * (1 << 16);
4862   double base =
4863       ((double)m_uHi) * pow * pow + ((double)m_uMid) * pow + ((double)m_uLo);
4864   int8_t scale = FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags);
4865   FX_BOOL bNeg = FXMATH_DECIMAL_FLAGS2NEG(m_uFlags);
4866   return (bNeg ? -1 : 1) * base * ::pow(10.0, -scale);
4867 }
SetScale(uint8_t newscale)4868 void CFX_Decimal::SetScale(uint8_t newscale) {
4869   uint8_t oldscale = FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags);
4870   if (newscale > oldscale) {
4871     uint64_t phi = m_uHi, pmid = m_uMid, plo = m_uLo;
4872     for (uint8_t iter = 0; iter < newscale - oldscale; iter++) {
4873       fxmath_decimal_helper_mul10(phi, pmid, plo);
4874     }
4875     m_uHi = (uint32_t)phi;
4876     m_uMid = (uint32_t)pmid;
4877     m_uLo = (uint32_t)plo;
4878     m_uFlags = FXMATH_DECIMAL_MAKEFLAGS(
4879         FXMATH_DECIMAL_FLAGS2NEG(m_uFlags) && IsNotZero(), newscale);
4880   } else if (newscale < oldscale) {
4881     uint64_t phi, pmid, plo;
4882     phi = 0, pmid = 0, plo = 5;
4883     {
4884       for (uint8_t iter = 0; iter < oldscale - newscale - 1; iter++) {
4885         fxmath_decimal_helper_mul10(phi, pmid, plo);
4886       }
4887     }
4888     phi += m_uHi;
4889     pmid += m_uMid;
4890     plo += m_uLo;
4891     fxmath_decimal_helper_normalize(phi, pmid, plo);
4892     {
4893       for (uint8_t iter = 0; iter < oldscale - newscale; iter++) {
4894         fxmath_decimal_helper_div10(phi, pmid, plo);
4895       }
4896     }
4897     m_uHi = (uint32_t)phi;
4898     m_uMid = (uint32_t)pmid;
4899     m_uLo = (uint32_t)plo;
4900     m_uFlags = FXMATH_DECIMAL_MAKEFLAGS(
4901         FXMATH_DECIMAL_FLAGS2NEG(m_uFlags) && IsNotZero(), newscale);
4902   }
4903 }
GetScale()4904 uint8_t CFX_Decimal::GetScale() {
4905   uint8_t oldscale = FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags);
4906   return oldscale;
4907 }
SetAbs()4908 void CFX_Decimal::SetAbs() {
4909   m_uFlags &= ~FXMATH_DECIMAL_NEGMASK;
4910 }
SetNegate()4911 void CFX_Decimal::SetNegate() {
4912   if (IsNotZero()) {
4913     m_uFlags ^= FXMATH_DECIMAL_NEGMASK;
4914   }
4915 }
FloorOrCeil(FX_BOOL bFloor)4916 void CFX_Decimal::FloorOrCeil(FX_BOOL bFloor) {
4917   uint64_t nums[3] = {m_uLo, m_uMid, m_uHi};
4918   FX_BOOL bDataLoss = FALSE;
4919   for (int i = FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags); i > 0; i--) {
4920     bDataLoss = fxmath_decimal_helper_div10_any(nums, 3) || bDataLoss;
4921   }
4922   if (bDataLoss && (bFloor ? FXMATH_DECIMAL_FLAGS2NEG(m_uFlags)
4923                            : !FXMATH_DECIMAL_FLAGS2NEG(m_uFlags))) {
4924     fxmath_decimal_helper_inc_any(nums, 3);
4925   }
4926   m_uHi = (uint32_t)nums[2];
4927   m_uMid = (uint32_t)nums[1];
4928   m_uLo = (uint32_t)nums[0];
4929   m_uFlags = FXMATH_DECIMAL_MAKEFLAGS(
4930       FXMATH_DECIMAL_FLAGS2NEG(m_uFlags) && IsNotZero(), 0);
4931 }
SetFloor()4932 void CFX_Decimal::SetFloor() {
4933   FloorOrCeil(TRUE);
4934 }
SetCeiling()4935 void CFX_Decimal::SetCeiling() {
4936   FloorOrCeil(FALSE);
4937 }
SetTruncate()4938 void CFX_Decimal::SetTruncate() {
4939   FloorOrCeil(!FXMATH_DECIMAL_FLAGS2NEG(m_uFlags));
4940 }
Swap(CFX_Decimal & val)4941 void CFX_Decimal::Swap(CFX_Decimal& val) {
4942   uint32_t tmp;
4943   tmp = m_uHi;
4944   m_uHi = val.m_uHi;
4945   val.m_uHi = tmp;
4946   tmp = m_uMid;
4947   m_uMid = val.m_uMid;
4948   val.m_uMid = tmp;
4949   tmp = m_uLo;
4950   m_uLo = val.m_uLo;
4951   val.m_uLo = tmp;
4952   tmp = m_uFlags;
4953   m_uFlags = val.m_uFlags;
4954   val.m_uFlags = tmp;
4955 }
Compare(const CFX_Decimal & val) const4956 int8_t CFX_Decimal::Compare(const CFX_Decimal& val) const {
4957   CFX_Decimal lhs = *this, rhs = val;
4958   int8_t retVal = 0;
4959   if (FXMATH_DECIMAL_FLAGS2SCALE(lhs.m_uFlags) !=
4960       FXMATH_DECIMAL_FLAGS2SCALE(rhs.m_uFlags)) {
4961     uint8_t scale = std::min(FXMATH_DECIMAL_FLAGS2SCALE(lhs.m_uFlags),
4962                              FXMATH_DECIMAL_FLAGS2SCALE(rhs.m_uFlags));
4963     lhs.SetScale(scale);
4964     rhs.SetScale(scale);
4965   }
4966   retVal = -(FXMATH_DECIMAL_FLAGS2NEG(lhs.m_uFlags) -
4967              FXMATH_DECIMAL_FLAGS2NEG(rhs.m_uFlags));
4968   if (retVal) {
4969     return retVal;
4970   }
4971   retVal = fxmath_decimal_helper_raw_compare(lhs.m_uHi, lhs.m_uMid, lhs.m_uLo,
4972                                              rhs.m_uHi, rhs.m_uMid, rhs.m_uLo);
4973   return (FXMATH_DECIMAL_FLAGS2NEG(lhs.m_uFlags) ? -retVal : retVal);
4974 }
AddOrMinus(const CFX_Decimal & val,FX_BOOL isAdding) const4975 CFX_Decimal CFX_Decimal::AddOrMinus(const CFX_Decimal& val,
4976                                     FX_BOOL isAdding) const {
4977   CFX_Decimal lhs = *this, rhs = val;
4978   if (FXMATH_DECIMAL_FLAGS2SCALE(lhs.m_uFlags) !=
4979       FXMATH_DECIMAL_FLAGS2SCALE(rhs.m_uFlags)) {
4980     uint8_t scale = std::max(FXMATH_DECIMAL_FLAGS2SCALE(lhs.m_uFlags),
4981                              FXMATH_DECIMAL_FLAGS2SCALE(rhs.m_uFlags));
4982     lhs.SetScale(scale);
4983     rhs.SetScale(scale);
4984   }
4985   if (!isAdding) {
4986     rhs.SetNegate();
4987   }
4988   FX_BOOL doRawAdd = (FXMATH_DECIMAL_FLAGS2NEG(lhs.m_uFlags) ==
4989                       FXMATH_DECIMAL_FLAGS2NEG(rhs.m_uFlags));
4990   if (doRawAdd) {
4991     uint64_t phi = lhs.m_uHi, pmid = lhs.m_uMid, plo = lhs.m_uLo;
4992     phi += rhs.m_uHi;
4993     pmid += rhs.m_uMid;
4994     plo += rhs.m_uLo;
4995     fxmath_decimal_helper_normalize(phi, pmid, plo);
4996     if (FXMATH_DECIMAL_RSHIFT32BIT(phi) &&
4997         FXMATH_DECIMAL_FLAGS2SCALE(lhs.m_uFlags) != 0) {
4998       fxmath_decimal_helper_div10(phi, pmid, plo);
4999       lhs.m_uFlags = FXMATH_DECIMAL_MAKEFLAGS(
5000           FXMATH_DECIMAL_FLAGS2NEG(lhs.m_uFlags),
5001           FXMATH_DECIMAL_FLAGS2SCALE(lhs.m_uFlags) - 1);
5002     }
5003     lhs.m_uHi = (uint32_t)phi;
5004     lhs.m_uMid = (uint32_t)pmid;
5005     lhs.m_uLo = (uint32_t)plo;
5006     return lhs;
5007   } else {
5008     if (fxmath_decimal_helper_raw_compare(lhs.m_uHi, lhs.m_uMid, lhs.m_uLo,
5009                                           rhs.m_uHi, rhs.m_uMid,
5010                                           rhs.m_uLo) < 0) {
5011       lhs.Swap(rhs);
5012     }
5013     lhs.m_uHi -= rhs.m_uHi;
5014     if (lhs.m_uMid < rhs.m_uMid) {
5015       lhs.m_uHi--;
5016     }
5017     lhs.m_uMid -= rhs.m_uMid;
5018     if (lhs.m_uLo < rhs.m_uLo) {
5019       if (!lhs.m_uMid) {
5020         lhs.m_uHi--;
5021       }
5022       lhs.m_uMid--;
5023     }
5024     lhs.m_uLo -= rhs.m_uLo;
5025     return lhs;
5026   }
5027 }
Multiply(const CFX_Decimal & val) const5028 CFX_Decimal CFX_Decimal::Multiply(const CFX_Decimal& val) const {
5029   uint64_t a[3] = {m_uLo, m_uMid, m_uHi},
5030            b[3] = {val.m_uLo, val.m_uMid, val.m_uHi};
5031   uint64_t c[6];
5032   fxmath_decimal_helper_raw_mul(a, 3, b, 3, c, 6);
5033   FX_BOOL neg = FXMATH_DECIMAL_FLAGS2NEG(m_uFlags) ^
5034                 FXMATH_DECIMAL_FLAGS2NEG(val.m_uFlags);
5035   uint8_t scale = FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags) +
5036                   FXMATH_DECIMAL_FLAGS2SCALE(val.m_uFlags);
5037   fxmath_decimal_helper_shrinkintorange(c, 6, 3, scale);
5038   return CFX_Decimal((uint32_t)c[0], (uint32_t)c[1], (uint32_t)c[2], neg,
5039                      scale);
5040 }
Divide(const CFX_Decimal & val) const5041 CFX_Decimal CFX_Decimal::Divide(const CFX_Decimal& val) const {
5042   if (!val.IsNotZero()) {
5043     return CFX_Decimal();
5044   }
5045   FX_BOOL neg = FXMATH_DECIMAL_FLAGS2NEG(m_uFlags) ^
5046                 FXMATH_DECIMAL_FLAGS2NEG(val.m_uFlags);
5047   uint64_t a[7] = {m_uLo, m_uMid, m_uHi},
5048            b[3] = {val.m_uLo, val.m_uMid, val.m_uHi}, c[7] = {0};
5049   uint8_t scale = 0;
5050   if (FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags) <
5051       FXMATH_DECIMAL_FLAGS2SCALE(val.m_uFlags)) {
5052     for (int i = FXMATH_DECIMAL_FLAGS2SCALE(val.m_uFlags) -
5053                  FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags);
5054          i > 0; i--) {
5055       fxmath_decimal_helper_mul10_any(a, 7);
5056     }
5057   } else {
5058     scale = FXMATH_DECIMAL_FLAGS2SCALE(m_uFlags) -
5059             FXMATH_DECIMAL_FLAGS2SCALE(val.m_uFlags);
5060   }
5061   uint8_t minscale = scale;
5062   if (!IsNotZero()) {
5063     return CFX_Decimal(0, 0, 0, 0, minscale);
5064   }
5065   while (!a[6]) {
5066     fxmath_decimal_helper_mul10_any(a, 7);
5067     scale++;
5068   }
5069   fxmath_decimal_helper_div10_any(a, 7);
5070   scale--;
5071   fxmath_decimal_helper_raw_div(a, 6, b, 3, c, 7);
5072   fxmath_decimal_helper_shrinkintorange(c, 6, 3, scale);
5073   fxmath_decimal_helper_truncate(c[2], c[1], c[0], scale, minscale);
5074   return CFX_Decimal((uint32_t)c[0], (uint32_t)c[1], (uint32_t)c[2], neg,
5075                      scale);
5076 }
Modulus(const CFX_Decimal & val) const5077 CFX_Decimal CFX_Decimal::Modulus(const CFX_Decimal& val) const {
5078   CFX_Decimal lhs = *this, rhs_abs = val;
5079   rhs_abs.SetAbs();
5080   if (!rhs_abs.IsNotZero()) {
5081     return *this;
5082   }
5083   while (TRUE) {
5084     CFX_Decimal lhs_abs = lhs;
5085     lhs_abs.SetAbs();
5086     if (lhs_abs < rhs_abs) {
5087       break;
5088     }
5089     CFX_Decimal quot = lhs / rhs_abs;
5090     quot.SetTruncate();
5091     lhs = lhs - quot * rhs_abs;
5092   }
5093   return lhs;
5094 }
operator ==(const CFX_Decimal & val) const5095 FX_BOOL CFX_Decimal::operator==(const CFX_Decimal& val) const {
5096   return Compare(val) == 0;
5097 }
operator <=(const CFX_Decimal & val) const5098 FX_BOOL CFX_Decimal::operator<=(const CFX_Decimal& val) const {
5099   return Compare(val) <= 0;
5100 }
operator >=(const CFX_Decimal & val) const5101 FX_BOOL CFX_Decimal::operator>=(const CFX_Decimal& val) const {
5102   return Compare(val) >= 0;
5103 }
operator !=(const CFX_Decimal & val) const5104 FX_BOOL CFX_Decimal::operator!=(const CFX_Decimal& val) const {
5105   return Compare(val) != 0;
5106 }
operator <(const CFX_Decimal & val) const5107 FX_BOOL CFX_Decimal::operator<(const CFX_Decimal& val) const {
5108   return Compare(val) < 0;
5109 }
operator >(const CFX_Decimal & val) const5110 FX_BOOL CFX_Decimal::operator>(const CFX_Decimal& val) const {
5111   return Compare(val) > 0;
5112 }
operator +(const CFX_Decimal & val) const5113 CFX_Decimal CFX_Decimal::operator+(const CFX_Decimal& val) const {
5114   return AddOrMinus(val, TRUE);
5115 }
operator -(const CFX_Decimal & val) const5116 CFX_Decimal CFX_Decimal::operator-(const CFX_Decimal& val) const {
5117   return AddOrMinus(val, FALSE);
5118 }
operator *(const CFX_Decimal & val) const5119 CFX_Decimal CFX_Decimal::operator*(const CFX_Decimal& val) const {
5120   return Multiply(val);
5121 }
operator /(const CFX_Decimal & val) const5122 CFX_Decimal CFX_Decimal::operator/(const CFX_Decimal& val) const {
5123   return Divide(val);
5124 }
operator %(const CFX_Decimal & val) const5125 CFX_Decimal CFX_Decimal::operator%(const CFX_Decimal& val) const {
5126   return Modulus(val);
5127 }
5128