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