Home | History | Annotate | Download | only in parser
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "xfa/fxfa/parser/cxfa_localevalue.h"
      8 
      9 #include <vector>
     10 
     11 #include "core/fxcrt/fx_extension.h"
     12 #include "third_party/base/ptr_util.h"
     13 #include "third_party/base/stl_util.h"
     14 #include "xfa/fgas/crt/cfgas_formatstring.h"
     15 #include "xfa/fxfa/parser/cxfa_document.h"
     16 #include "xfa/fxfa/parser/cxfa_localemgr.h"
     17 #include "xfa/fxfa/parser/xfa_utils.h"
     18 
     19 namespace {
     20 
     21 FX_LOCALECATEGORY ValueCategory(FX_LOCALECATEGORY eCategory,
     22                                 uint32_t dwValueType) {
     23   if (eCategory != FX_LOCALECATEGORY_Unknown)
     24     return eCategory;
     25 
     26   switch (dwValueType) {
     27     case XFA_VT_BOOLEAN:
     28     case XFA_VT_INTEGER:
     29     case XFA_VT_DECIMAL:
     30     case XFA_VT_FLOAT:
     31       return FX_LOCALECATEGORY_Num;
     32     case XFA_VT_TEXT:
     33       return FX_LOCALECATEGORY_Text;
     34     case XFA_VT_DATE:
     35       return FX_LOCALECATEGORY_Date;
     36     case XFA_VT_TIME:
     37       return FX_LOCALECATEGORY_Time;
     38     case XFA_VT_DATETIME:
     39       return FX_LOCALECATEGORY_DateTime;
     40   }
     41   return FX_LOCALECATEGORY_Unknown;
     42 }
     43 
     44 bool ValueSplitDateTime(const WideString& wsDateTime,
     45                         WideString& wsDate,
     46                         WideString& wsTime) {
     47   wsDate = L"";
     48   wsTime = L"";
     49   if (wsDateTime.IsEmpty())
     50     return false;
     51 
     52   auto nSplitIndex = wsDateTime.Find('T');
     53   if (!nSplitIndex.has_value())
     54     nSplitIndex = wsDateTime.Find(' ');
     55   if (!nSplitIndex.has_value())
     56     return false;
     57 
     58   wsDate = wsDateTime.Left(nSplitIndex.value());
     59   wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex.value() - 1);
     60   return true;
     61 }
     62 
     63 }  // namespace
     64 
     65 CXFA_LocaleValue::CXFA_LocaleValue()
     66     : m_pLocaleMgr(nullptr), m_dwType(XFA_VT_NULL), m_bValid(true) {}
     67 
     68 CXFA_LocaleValue::CXFA_LocaleValue(const CXFA_LocaleValue& value)
     69     : m_pLocaleMgr(value.m_pLocaleMgr),
     70       m_wsValue(value.m_wsValue),
     71       m_dwType(value.m_dwType),
     72       m_bValid(value.m_bValid) {}
     73 
     74 CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType, CXFA_LocaleMgr* pLocaleMgr)
     75     : m_pLocaleMgr(pLocaleMgr),
     76       m_dwType(dwType),
     77       m_bValid(m_dwType != XFA_VT_NULL) {}
     78 
     79 CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType,
     80                                    const WideString& wsValue,
     81                                    CXFA_LocaleMgr* pLocaleMgr)
     82     : m_pLocaleMgr(pLocaleMgr),
     83       m_wsValue(wsValue),
     84       m_dwType(dwType),
     85       m_bValid(ValidateCanonicalValue(wsValue, dwType)) {}
     86 
     87 CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType,
     88                                    const WideString& wsValue,
     89                                    const WideString& wsFormat,
     90                                    IFX_Locale* pLocale,
     91                                    CXFA_LocaleMgr* pLocaleMgr)
     92     : m_pLocaleMgr(pLocaleMgr),
     93       m_dwType(dwType),
     94       m_bValid(ParsePatternValue(wsValue, wsFormat, pLocale)) {}
     95 
     96 CXFA_LocaleValue& CXFA_LocaleValue::operator=(const CXFA_LocaleValue& value) {
     97   m_wsValue = value.m_wsValue;
     98   m_dwType = value.m_dwType;
     99   m_bValid = value.m_bValid;
    100   m_pLocaleMgr = value.m_pLocaleMgr;
    101   return *this;
    102 }
    103 
    104 CXFA_LocaleValue::~CXFA_LocaleValue() {}
    105 
    106 bool CXFA_LocaleValue::ValidateValue(const WideString& wsValue,
    107                                      const WideString& wsPattern,
    108                                      IFX_Locale* pLocale,
    109                                      WideString* pMatchFormat) {
    110   WideString wsOutput;
    111   IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
    112   if (pLocale)
    113     m_pLocaleMgr->SetDefLocale(pLocale);
    114 
    115   auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr);
    116   std::vector<WideString> wsPatterns;
    117   pFormat->SplitFormatString(wsPattern, &wsPatterns);
    118 
    119   bool bRet = false;
    120   int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
    121   int32_t i = 0;
    122   for (; i < iCount && !bRet; i++) {
    123     WideString wsFormat = wsPatterns[i];
    124     switch (ValueCategory(pFormat->GetCategory(wsFormat), m_dwType)) {
    125       case FX_LOCALECATEGORY_Null:
    126         bRet = pFormat->ParseNull(wsValue, wsFormat);
    127         if (!bRet)
    128           bRet = wsValue.IsEmpty();
    129         break;
    130       case FX_LOCALECATEGORY_Zero:
    131         bRet = pFormat->ParseZero(wsValue, wsFormat);
    132         if (!bRet)
    133           bRet = wsValue == L"0";
    134         break;
    135       case FX_LOCALECATEGORY_Num: {
    136         WideString fNum;
    137         bRet = pFormat->ParseNum(wsValue, wsFormat, &fNum);
    138         if (!bRet)
    139           bRet = pFormat->FormatNum(wsValue, wsFormat, &wsOutput);
    140         break;
    141       }
    142       case FX_LOCALECATEGORY_Text:
    143         bRet = pFormat->ParseText(wsValue, wsFormat, &wsOutput);
    144         wsOutput.clear();
    145         if (!bRet)
    146           bRet = pFormat->FormatText(wsValue, wsFormat, &wsOutput);
    147         break;
    148       case FX_LOCALECATEGORY_Date: {
    149         CFX_DateTime dt;
    150         bRet = ValidateCanonicalDate(wsValue, &dt);
    151         if (!bRet) {
    152           bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date,
    153                                         &dt);
    154           if (!bRet) {
    155             bRet = pFormat->FormatDateTime(wsValue, wsFormat,
    156                                            FX_DATETIMETYPE_Date, &wsOutput);
    157           }
    158         }
    159         break;
    160       }
    161       case FX_LOCALECATEGORY_Time: {
    162         CFX_DateTime dt;
    163         bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time,
    164                                       &dt);
    165         if (!bRet) {
    166           bRet = pFormat->FormatDateTime(wsValue, wsFormat,
    167                                          FX_DATETIMETYPE_Time, &wsOutput);
    168         }
    169         break;
    170       }
    171       case FX_LOCALECATEGORY_DateTime: {
    172         CFX_DateTime dt;
    173         bRet = pFormat->ParseDateTime(wsValue, wsFormat,
    174                                       FX_DATETIMETYPE_DateTime, &dt);
    175         if (!bRet) {
    176           bRet = pFormat->FormatDateTime(wsValue, wsFormat,
    177                                          FX_DATETIMETYPE_DateTime, &wsOutput);
    178         }
    179         break;
    180       }
    181       default:
    182         bRet = false;
    183         break;
    184     }
    185   }
    186   if (bRet && pMatchFormat)
    187     *pMatchFormat = wsPatterns[i - 1];
    188   if (pLocale)
    189     m_pLocaleMgr->SetDefLocale(locale);
    190 
    191   return bRet;
    192 }
    193 
    194 double CXFA_LocaleValue::GetDoubleNum() const {
    195   if (m_bValid && (m_dwType == XFA_VT_BOOLEAN || m_dwType == XFA_VT_INTEGER ||
    196                    m_dwType == XFA_VT_DECIMAL || m_dwType == XFA_VT_FLOAT)) {
    197     int64_t nIntegral = 0;
    198     uint32_t dwFractional = 0;
    199     int32_t nExponent = 0;
    200     int32_t cc = 0;
    201     bool bNegative = false;
    202     bool bExpSign = false;
    203     const wchar_t* str = m_wsValue.c_str();
    204     int len = m_wsValue.GetLength();
    205     while (FXSYS_iswspace(str[cc]) && cc < len)
    206       cc++;
    207 
    208     if (cc >= len)
    209       return 0;
    210     if (str[0] == '+') {
    211       cc++;
    212     } else if (str[0] == '-') {
    213       bNegative = true;
    214       cc++;
    215     }
    216 
    217     int32_t nIntegralLen = 0;
    218     while (cc < len) {
    219       if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc]) ||
    220           nIntegralLen > 17) {
    221         break;
    222       }
    223       nIntegral = nIntegral * 10 + str[cc] - '0';
    224       cc++;
    225       nIntegralLen++;
    226     }
    227 
    228     nIntegral = bNegative ? -nIntegral : nIntegral;
    229     int32_t scale = 0;
    230     double fraction = 0.0;
    231     if (cc < len && str[cc] == '.') {
    232       cc++;
    233       while (cc < len) {
    234         fraction += XFA_GetFractionalScale(scale) * (str[cc] - '0');
    235         scale++;
    236         cc++;
    237         if (scale == XFA_GetMaxFractionalScale() ||
    238             !FXSYS_isDecimalDigit(str[cc])) {
    239           break;
    240         }
    241       }
    242       dwFractional = static_cast<uint32_t>(fraction * 4294967296.0);
    243     }
    244     if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) {
    245       cc++;
    246       if (cc < len) {
    247         if (str[cc] == '+') {
    248           cc++;
    249         } else if (str[cc] == '-') {
    250           bExpSign = true;
    251           cc++;
    252         }
    253       }
    254       while (cc < len) {
    255         if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc]))
    256           break;
    257 
    258         nExponent = nExponent * 10 + str[cc] - '0';
    259         cc++;
    260       }
    261       nExponent = bExpSign ? -nExponent : nExponent;
    262     }
    263 
    264     double dValue = dwFractional / 4294967296.0;
    265     dValue = nIntegral + (nIntegral >= 0 ? dValue : -dValue);
    266     if (nExponent != 0)
    267       dValue *= FXSYS_pow(10, static_cast<float>(nExponent));
    268 
    269     return dValue;
    270   }
    271   return 0;
    272 }
    273 
    274 CFX_DateTime CXFA_LocaleValue::GetDate() const {
    275   if (!m_bValid || m_dwType != XFA_VT_DATE)
    276     return CFX_DateTime();
    277 
    278   CFX_DateTime dt;
    279   FX_DateFromCanonical(m_wsValue, &dt);
    280   return dt;
    281 }
    282 
    283 CFX_DateTime CXFA_LocaleValue::GetTime() const {
    284   if (!m_bValid || m_dwType != XFA_VT_TIME)
    285     return CFX_DateTime();
    286 
    287   CFX_DateTime dt;
    288   FX_TimeFromCanonical(m_wsValue.AsStringView(), &dt,
    289                        m_pLocaleMgr->GetDefLocale());
    290   return dt;
    291 }
    292 
    293 bool CXFA_LocaleValue::SetDate(const CFX_DateTime& d) {
    294   m_dwType = XFA_VT_DATE;
    295   m_wsValue = WideString::Format(L"%04d-%02d-%02d", d.GetYear(), d.GetMonth(),
    296                                  d.GetDay());
    297   return true;
    298 }
    299 
    300 bool CXFA_LocaleValue::SetTime(const CFX_DateTime& t) {
    301   m_dwType = XFA_VT_TIME;
    302   m_wsValue = WideString::Format(L"%02d:%02d:%02d", t.GetHour(), t.GetMinute(),
    303                                  t.GetSecond());
    304   if (t.GetMillisecond() > 0)
    305     m_wsValue += WideString::Format(L"%:03d", t.GetMillisecond());
    306   return true;
    307 }
    308 
    309 bool CXFA_LocaleValue::SetDateTime(const CFX_DateTime& dt) {
    310   m_dwType = XFA_VT_DATETIME;
    311   m_wsValue = WideString::Format(L"%04d-%02d-%02dT%02d:%02d:%02d", dt.GetYear(),
    312                                  dt.GetMonth(), dt.GetDay(), dt.GetHour(),
    313                                  dt.GetMinute(), dt.GetSecond());
    314   if (dt.GetMillisecond() > 0)
    315     m_wsValue += WideString::Format(L"%:03d", dt.GetMillisecond());
    316   return true;
    317 }
    318 
    319 bool CXFA_LocaleValue::FormatPatterns(WideString& wsResult,
    320                                       const WideString& wsFormat,
    321                                       IFX_Locale* pLocale,
    322                                       XFA_VALUEPICTURE eValueType) const {
    323   auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr);
    324   std::vector<WideString> wsPatterns;
    325   pFormat->SplitFormatString(wsFormat, &wsPatterns);
    326   wsResult.clear();
    327   int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
    328   for (int32_t i = 0; i < iCount; i++) {
    329     if (FormatSinglePattern(wsResult, wsPatterns[i], pLocale, eValueType))
    330       return true;
    331   }
    332   return false;
    333 }
    334 
    335 bool CXFA_LocaleValue::FormatSinglePattern(WideString& wsResult,
    336                                            const WideString& wsFormat,
    337                                            IFX_Locale* pLocale,
    338                                            XFA_VALUEPICTURE eValueType) const {
    339   IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
    340   if (pLocale)
    341     m_pLocaleMgr->SetDefLocale(pLocale);
    342 
    343   wsResult.clear();
    344   bool bRet = false;
    345   auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr);
    346   FX_LOCALECATEGORY eCategory =
    347       ValueCategory(pFormat->GetCategory(wsFormat), m_dwType);
    348   switch (eCategory) {
    349     case FX_LOCALECATEGORY_Null:
    350       if (m_wsValue.IsEmpty())
    351         bRet = pFormat->FormatNull(wsFormat, &wsResult);
    352       break;
    353     case FX_LOCALECATEGORY_Zero:
    354       if (m_wsValue == L"0")
    355         bRet = pFormat->FormatZero(wsFormat, &wsResult);
    356       break;
    357     case FX_LOCALECATEGORY_Num:
    358       bRet = pFormat->FormatNum(m_wsValue, wsFormat, &wsResult);
    359       break;
    360     case FX_LOCALECATEGORY_Text:
    361       bRet = pFormat->FormatText(m_wsValue, wsFormat, &wsResult);
    362       break;
    363     case FX_LOCALECATEGORY_Date:
    364       bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, FX_DATETIMETYPE_Date,
    365                                      &wsResult);
    366       break;
    367     case FX_LOCALECATEGORY_Time:
    368       bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, FX_DATETIMETYPE_Time,
    369                                      &wsResult);
    370       break;
    371     case FX_LOCALECATEGORY_DateTime:
    372       bRet = pFormat->FormatDateTime(m_wsValue, wsFormat,
    373                                      FX_DATETIMETYPE_DateTime, &wsResult);
    374       break;
    375     default:
    376       wsResult = m_wsValue;
    377       bRet = true;
    378   }
    379   if (!bRet && (eCategory != FX_LOCALECATEGORY_Num ||
    380                 eValueType != XFA_VALUEPICTURE_Display)) {
    381     wsResult = m_wsValue;
    382   }
    383   if (pLocale)
    384     m_pLocaleMgr->SetDefLocale(locale);
    385 
    386   return bRet;
    387 }
    388 
    389 bool CXFA_LocaleValue::ValidateCanonicalValue(const WideString& wsValue,
    390                                               uint32_t dwVType) {
    391   if (wsValue.IsEmpty())
    392     return true;
    393 
    394   CFX_DateTime dt;
    395   switch (dwVType) {
    396     case XFA_VT_DATE: {
    397       if (ValidateCanonicalDate(wsValue, &dt))
    398         return true;
    399 
    400       WideString wsDate;
    401       WideString wsTime;
    402       if (ValueSplitDateTime(wsValue, wsDate, wsTime) &&
    403           ValidateCanonicalDate(wsDate, &dt)) {
    404         return true;
    405       }
    406       return false;
    407     }
    408     case XFA_VT_TIME: {
    409       if (ValidateCanonicalTime(wsValue))
    410         return true;
    411 
    412       WideString wsDate;
    413       WideString wsTime;
    414       if (ValueSplitDateTime(wsValue, wsDate, wsTime) &&
    415           ValidateCanonicalTime(wsTime)) {
    416         return true;
    417       }
    418       return false;
    419     }
    420     case XFA_VT_DATETIME: {
    421       WideString wsDate, wsTime;
    422       if (ValueSplitDateTime(wsValue, wsDate, wsTime) &&
    423           ValidateCanonicalDate(wsDate, &dt) && ValidateCanonicalTime(wsTime)) {
    424         return true;
    425       }
    426     } break;
    427   }
    428   return true;
    429 }
    430 
    431 bool CXFA_LocaleValue::ValidateCanonicalDate(const WideString& wsDate,
    432                                              CFX_DateTime* unDate) {
    433   static const uint16_t LastDay[12] = {31, 28, 31, 30, 31, 30,
    434                                        31, 31, 30, 31, 30, 31};
    435   static const uint16_t wCountY = 4;
    436   static const uint16_t wCountM = 2;
    437   static const uint16_t wCountD = 2;
    438   int nLen = wsDate.GetLength();
    439   if (nLen < wCountY || nLen > wCountY + wCountM + wCountD + 2)
    440     return false;
    441 
    442   const bool bSymbol = wsDate.Contains(0x2D);
    443   uint16_t wYear = 0;
    444   uint16_t wMonth = 0;
    445   uint16_t wDay = 0;
    446   const wchar_t* pDate = wsDate.c_str();
    447   int nIndex = 0;
    448   int nStart = 0;
    449   while (pDate[nIndex] != '\0' && nIndex < wCountY) {
    450     if (!FXSYS_isDecimalDigit(pDate[nIndex]))
    451       return false;
    452 
    453     wYear = (pDate[nIndex] - '0') + wYear * 10;
    454     nIndex++;
    455   }
    456   if (bSymbol) {
    457     if (pDate[nIndex] != 0x2D)
    458       return false;
    459     nIndex++;
    460   }
    461 
    462   nStart = nIndex;
    463   while (pDate[nIndex] != '\0' && nIndex - nStart < wCountM && nIndex < nLen) {
    464     if (!FXSYS_isDecimalDigit(pDate[nIndex]))
    465       return false;
    466 
    467     wMonth = (pDate[nIndex] - '0') + wMonth * 10;
    468     nIndex++;
    469   }
    470   if (bSymbol) {
    471     if (pDate[nIndex] != 0x2D)
    472       return false;
    473     nIndex++;
    474   }
    475 
    476   nStart = nIndex;
    477   while (pDate[nIndex] != '\0' && nIndex - nStart < wCountD && nIndex < nLen) {
    478     if (!FXSYS_isDecimalDigit(pDate[nIndex]))
    479       return false;
    480 
    481     wDay = (pDate[nIndex] - '0') + wDay * 10;
    482     nIndex++;
    483   }
    484   if (nIndex != nLen)
    485     return false;
    486   if (wYear < 1900 || wYear > 2029)
    487     return false;
    488   if (wMonth < 1 || wMonth > 12)
    489     return wMonth == 0 && nLen == wCountY;
    490   if (wDay < 1)
    491     return wDay == 0 && (nLen == wCountY + wCountM);
    492   if (wMonth == 2) {
    493     if (wYear % 400 == 0 || (wYear % 100 != 0 && wYear % 4 == 0)) {
    494       if (wDay > 29)
    495         return false;
    496     } else if (wDay > 28) {
    497       return false;
    498     }
    499   } else if (wDay > LastDay[wMonth - 1]) {
    500     return false;
    501   }
    502 
    503   unDate->SetDate(wYear, static_cast<uint8_t>(wMonth),
    504                   static_cast<uint8_t>(wDay));
    505   return true;
    506 }
    507 
    508 bool CXFA_LocaleValue::ValidateCanonicalTime(const WideString& wsTime) {
    509   int nLen = wsTime.GetLength();
    510   if (nLen < 2)
    511     return false;
    512 
    513   const uint16_t wCountH = 2;
    514   const uint16_t wCountM = 2;
    515   const uint16_t wCountS = 2;
    516   const uint16_t wCountF = 3;
    517   const bool bSymbol = wsTime.Contains(':');
    518   uint16_t wHour = 0;
    519   uint16_t wMinute = 0;
    520   uint16_t wSecond = 0;
    521   uint16_t wFraction = 0;
    522   const wchar_t* pTime = wsTime.c_str();
    523   int nIndex = 0;
    524   int nStart = 0;
    525   while (nIndex - nStart < wCountH && pTime[nIndex]) {
    526     if (!FXSYS_isDecimalDigit(pTime[nIndex]))
    527       return false;
    528     wHour = pTime[nIndex] - '0' + wHour * 10;
    529     nIndex++;
    530   }
    531   if (bSymbol) {
    532     if (nIndex < nLen && pTime[nIndex] != ':')
    533       return false;
    534     nIndex++;
    535   }
    536 
    537   nStart = nIndex;
    538   while (nIndex - nStart < wCountM && nIndex < nLen && pTime[nIndex]) {
    539     if (!FXSYS_isDecimalDigit(pTime[nIndex]))
    540       return false;
    541     wMinute = pTime[nIndex] - '0' + wMinute * 10;
    542     nIndex++;
    543   }
    544   if (bSymbol) {
    545     if (nIndex < nLen && pTime[nIndex] != ':')
    546       return false;
    547     nIndex++;
    548   }
    549   nStart = nIndex;
    550   while (nIndex - nStart < wCountS && nIndex < nLen && pTime[nIndex]) {
    551     if (!FXSYS_isDecimalDigit(pTime[nIndex]))
    552       return false;
    553     wSecond = pTime[nIndex] - '0' + wSecond * 10;
    554     nIndex++;
    555   }
    556   auto pos = wsTime.Find('.');
    557   if (pos.has_value() && pos.value() != 0) {
    558     if (pTime[nIndex] != '.')
    559       return false;
    560     nIndex++;
    561     nStart = nIndex;
    562     while (nIndex - nStart < wCountF && nIndex < nLen && pTime[nIndex]) {
    563       if (!FXSYS_isDecimalDigit(pTime[nIndex]))
    564         return false;
    565       wFraction = pTime[nIndex] - '0' + wFraction * 10;
    566       nIndex++;
    567     }
    568   }
    569   if (nIndex < nLen) {
    570     if (pTime[nIndex] == 'Z') {
    571       nIndex++;
    572     } else if (pTime[nIndex] == '-' || pTime[nIndex] == '+') {
    573       int16_t nOffsetH = 0;
    574       int16_t nOffsetM = 0;
    575       nIndex++;
    576       nStart = nIndex;
    577       while (nIndex - nStart < wCountH && nIndex < nLen && pTime[nIndex]) {
    578         if (!FXSYS_isDecimalDigit(pTime[nIndex]))
    579           return false;
    580         nOffsetH = pTime[nIndex] - '0' + nOffsetH * 10;
    581         nIndex++;
    582       }
    583       if (bSymbol) {
    584         if (nIndex < nLen && pTime[nIndex] != ':')
    585           return false;
    586         nIndex++;
    587       }
    588       nStart = nIndex;
    589       while (nIndex - nStart < wCountM && nIndex < nLen && pTime[nIndex]) {
    590         if (!FXSYS_isDecimalDigit(pTime[nIndex]))
    591           return false;
    592         nOffsetM = pTime[nIndex] - '0' + nOffsetM * 10;
    593         nIndex++;
    594       }
    595       if (nOffsetH > 12 || nOffsetM >= 60)
    596         return false;
    597     }
    598   }
    599   return nIndex == nLen && wHour < 24 && wMinute < 60 && wSecond < 60 &&
    600          wFraction <= 999;
    601 }
    602 
    603 bool CXFA_LocaleValue::ParsePatternValue(const WideString& wsValue,
    604                                          const WideString& wsPattern,
    605                                          IFX_Locale* pLocale) {
    606   IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
    607   if (pLocale)
    608     m_pLocaleMgr->SetDefLocale(pLocale);
    609 
    610   auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr);
    611   std::vector<WideString> wsPatterns;
    612   pFormat->SplitFormatString(wsPattern, &wsPatterns);
    613   bool bRet = false;
    614   int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
    615   for (int32_t i = 0; i < iCount && !bRet; i++) {
    616     WideString wsFormat = wsPatterns[i];
    617     switch (ValueCategory(pFormat->GetCategory(wsFormat), m_dwType)) {
    618       case FX_LOCALECATEGORY_Null:
    619         bRet = pFormat->ParseNull(wsValue, wsFormat);
    620         if (bRet)
    621           m_wsValue.clear();
    622         break;
    623       case FX_LOCALECATEGORY_Zero:
    624         bRet = pFormat->ParseZero(wsValue, wsFormat);
    625         if (bRet)
    626           m_wsValue = L"0";
    627         break;
    628       case FX_LOCALECATEGORY_Num: {
    629         WideString fNum;
    630         bRet = pFormat->ParseNum(wsValue, wsFormat, &fNum);
    631         if (bRet)
    632           m_wsValue = fNum;
    633         break;
    634       }
    635       case FX_LOCALECATEGORY_Text:
    636         bRet = pFormat->ParseText(wsValue, wsFormat, &m_wsValue);
    637         break;
    638       case FX_LOCALECATEGORY_Date: {
    639         CFX_DateTime dt;
    640         bRet = ValidateCanonicalDate(wsValue, &dt);
    641         if (!bRet) {
    642           bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date,
    643                                         &dt);
    644         }
    645         if (bRet)
    646           SetDate(dt);
    647         break;
    648       }
    649       case FX_LOCALECATEGORY_Time: {
    650         CFX_DateTime dt;
    651         bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time,
    652                                       &dt);
    653         if (bRet)
    654           SetTime(dt);
    655         break;
    656       }
    657       case FX_LOCALECATEGORY_DateTime: {
    658         CFX_DateTime dt;
    659         bRet = pFormat->ParseDateTime(wsValue, wsFormat,
    660                                       FX_DATETIMETYPE_DateTime, &dt);
    661         if (bRet)
    662           SetDateTime(dt);
    663         break;
    664       }
    665       default:
    666         m_wsValue = wsValue;
    667         bRet = true;
    668         break;
    669     }
    670   }
    671   if (!bRet)
    672     m_wsValue = wsValue;
    673 
    674   if (pLocale)
    675     m_pLocaleMgr->SetDefLocale(locale);
    676 
    677   return bRet;
    678 }
    679 
    680 void CXFA_LocaleValue::GetNumericFormat(WideString& wsFormat,
    681                                         int32_t nIntLen,
    682                                         int32_t nDecLen) {
    683   ASSERT(wsFormat.IsEmpty());
    684   ASSERT(nIntLen >= -1 && nDecLen >= -1);
    685 
    686   int32_t nTotalLen = (nIntLen >= 0 ? nIntLen : 2) + 1 +
    687                       (nDecLen >= 0 ? nDecLen : 2) + (nDecLen == 0 ? 0 : 1);
    688   wchar_t* lpBuf = wsFormat.GetBuffer(nTotalLen);
    689   int32_t nPos = 0;
    690   lpBuf[nPos++] = L's';
    691 
    692   if (nIntLen == -1) {
    693     lpBuf[nPos++] = L'z';
    694     lpBuf[nPos++] = L'*';
    695   } else {
    696     while (nIntLen) {
    697       lpBuf[nPos++] = L'z';
    698       nIntLen--;
    699     }
    700   }
    701   if (nDecLen != 0) {
    702     lpBuf[nPos++] = L'.';
    703   }
    704   if (nDecLen == -1) {
    705     lpBuf[nPos++] = L'z';
    706     lpBuf[nPos++] = L'*';
    707   } else {
    708     while (nDecLen) {
    709       lpBuf[nPos++] = L'z';
    710       nDecLen--;
    711     }
    712   }
    713   wsFormat.ReleaseBuffer(nTotalLen);
    714 }
    715 
    716 bool CXFA_LocaleValue::ValidateNumericTemp(const WideString& wsNumeric,
    717                                            const WideString& wsFormat,
    718                                            IFX_Locale* pLocale) {
    719   if (wsFormat.IsEmpty() || wsNumeric.IsEmpty())
    720     return true;
    721 
    722   const wchar_t* pNum = wsNumeric.c_str();
    723   const wchar_t* pFmt = wsFormat.c_str();
    724   int32_t n = 0;
    725   int32_t nf = 0;
    726   wchar_t c = pNum[n];
    727   wchar_t cf = pFmt[nf];
    728   if (cf == L's') {
    729     if (c == L'-' || c == L'+')
    730       ++n;
    731     ++nf;
    732   }
    733 
    734   bool bLimit = true;
    735   int32_t nCount = wsNumeric.GetLength();
    736   int32_t nCountFmt = wsFormat.GetLength();
    737   while (n < nCount && (bLimit ? nf < nCountFmt : true) &&
    738          FXSYS_isDecimalDigit(c = pNum[n])) {
    739     if (bLimit == true) {
    740       if ((cf = pFmt[nf]) == L'*')
    741         bLimit = false;
    742       else if (cf == L'z')
    743         nf++;
    744       else
    745         return false;
    746     }
    747     n++;
    748   }
    749   if (n == nCount)
    750     return true;
    751   if (nf == nCountFmt)
    752     return false;
    753 
    754   while (nf < nCountFmt && (cf = pFmt[nf]) != L'.') {
    755     ASSERT(cf == L'z' || cf == L'*');
    756     ++nf;
    757   }
    758 
    759   WideString wsDecimalSymbol;
    760   if (pLocale)
    761     wsDecimalSymbol = pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal);
    762   else
    763     wsDecimalSymbol = WideString(L'.');
    764 
    765   if (pFmt[nf] != L'.')
    766     return false;
    767   if (wsDecimalSymbol != WideStringView(c) && c != L'.')
    768     return false;
    769 
    770   ++nf;
    771   ++n;
    772   bLimit = true;
    773   while (n < nCount && (bLimit ? nf < nCountFmt : true) &&
    774          FXSYS_isDecimalDigit(c = pNum[n])) {
    775     if (bLimit == true) {
    776       if ((cf = pFmt[nf]) == L'*')
    777         bLimit = false;
    778       else if (cf == L'z')
    779         nf++;
    780       else
    781         return false;
    782     }
    783     n++;
    784   }
    785   return n == nCount;
    786 }
    787