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