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