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