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/xfa_localevalue.h"
8
9#include <vector>
10
11#include "core/fxcrt/fx_ext.h"
12#include "third_party/base/ptr_util.h"
13#include "third_party/base/stl_util.h"
14#include "xfa/fgas/localization/fgas_localeimp.h"
15#include "xfa/fxfa/parser/cxfa_document.h"
16#include "xfa/fxfa/parser/xfa_localemgr.h"
17#include "xfa/fxfa/parser/xfa_object.h"
18#include "xfa/fxfa/parser/xfa_utils.h"
19
20static const FX_DOUBLE fraction_scales[] = {0.1,
21                                            0.01,
22                                            0.001,
23                                            0.0001,
24                                            0.00001,
25                                            0.000001,
26                                            0.0000001,
27                                            0.00000001,
28                                            0.000000001,
29                                            0.0000000001,
30                                            0.00000000001,
31                                            0.000000000001,
32                                            0.0000000000001,
33                                            0.00000000000001,
34                                            0.000000000000001,
35                                            0.0000000000000001};
36CXFA_LocaleValue::CXFA_LocaleValue() {
37  m_dwType = XFA_VT_NULL;
38  m_bValid = true;
39  m_pLocaleMgr = nullptr;
40}
41CXFA_LocaleValue::CXFA_LocaleValue(const CXFA_LocaleValue& value) {
42  m_dwType = XFA_VT_NULL;
43  m_bValid = true;
44  m_pLocaleMgr = nullptr;
45  *this = value;
46}
47CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType,
48                                   CXFA_LocaleMgr* pLocaleMgr) {
49  m_dwType = dwType;
50  m_bValid = (m_dwType != XFA_VT_NULL);
51  m_pLocaleMgr = pLocaleMgr;
52}
53CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType,
54                                   const CFX_WideString& wsValue,
55                                   CXFA_LocaleMgr* pLocaleMgr) {
56  m_wsValue = wsValue;
57  m_dwType = dwType;
58  m_pLocaleMgr = pLocaleMgr;
59  m_bValid = ValidateCanonicalValue(wsValue, dwType);
60}
61CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType,
62                                   const CFX_WideString& wsValue,
63                                   const CFX_WideString& wsFormat,
64                                   IFX_Locale* pLocale,
65                                   CXFA_LocaleMgr* pLocaleMgr) {
66  m_pLocaleMgr = pLocaleMgr;
67  m_bValid = true;
68  m_dwType = dwType;
69  m_bValid = ParsePatternValue(wsValue, wsFormat, pLocale);
70}
71CXFA_LocaleValue& CXFA_LocaleValue::operator=(const CXFA_LocaleValue& value) {
72  m_wsValue = value.m_wsValue;
73  m_dwType = value.m_dwType;
74  m_bValid = value.m_bValid;
75  m_pLocaleMgr = value.m_pLocaleMgr;
76  return *this;
77}
78CXFA_LocaleValue::~CXFA_LocaleValue() {}
79static FX_LOCALECATEGORY XFA_ValugeCategory(FX_LOCALECATEGORY eCategory,
80                                            uint32_t dwValueType) {
81  if (eCategory == FX_LOCALECATEGORY_Unknown) {
82    switch (dwValueType) {
83      case XFA_VT_BOOLEAN:
84      case XFA_VT_INTEGER:
85      case XFA_VT_DECIMAL:
86      case XFA_VT_FLOAT:
87        return FX_LOCALECATEGORY_Num;
88      case XFA_VT_TEXT:
89        return FX_LOCALECATEGORY_Text;
90      case XFA_VT_DATE:
91        return FX_LOCALECATEGORY_Date;
92      case XFA_VT_TIME:
93        return FX_LOCALECATEGORY_Time;
94      case XFA_VT_DATETIME:
95        return FX_LOCALECATEGORY_DateTime;
96    }
97  }
98  return eCategory;
99}
100
101bool CXFA_LocaleValue::ValidateValue(const CFX_WideString& wsValue,
102                                     const CFX_WideString& wsPattern,
103                                     IFX_Locale* pLocale,
104                                     CFX_WideString* pMatchFormat) {
105  CFX_WideString wsOutput;
106  IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
107  if (pLocale)
108    m_pLocaleMgr->SetDefLocale(pLocale);
109
110  auto pFormat = pdfium::MakeUnique<CFX_FormatString>(m_pLocaleMgr, false);
111  std::vector<CFX_WideString> wsPatterns;
112  pFormat->SplitFormatString(wsPattern, wsPatterns);
113
114  bool bRet = false;
115  int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
116  int32_t i = 0;
117  for (; i < iCount && !bRet; i++) {
118    CFX_WideString wsFormat = wsPatterns[i];
119    FX_LOCALECATEGORY eCategory = pFormat->GetCategory(wsFormat);
120    eCategory = XFA_ValugeCategory(eCategory, m_dwType);
121    switch (eCategory) {
122      case FX_LOCALECATEGORY_Null:
123        bRet = pFormat->ParseNull(wsValue, wsFormat);
124        if (!bRet) {
125          bRet = wsValue.IsEmpty();
126        }
127        break;
128      case FX_LOCALECATEGORY_Zero:
129        bRet = pFormat->ParseZero(wsValue, wsFormat);
130        if (!bRet) {
131          bRet = wsValue == L"0";
132        }
133        break;
134      case FX_LOCALECATEGORY_Num: {
135        CFX_WideString fNum;
136        bRet = pFormat->ParseNum(wsValue, wsFormat, fNum);
137        if (!bRet) {
138          bRet = pFormat->FormatNum(wsValue, wsFormat, wsOutput);
139        }
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        }
148        break;
149      case FX_LOCALECATEGORY_Date: {
150        CFX_Unitime dt;
151        bRet = ValidateCanonicalDate(wsValue, dt);
152        if (!bRet) {
153          bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date,
154                                        dt);
155          if (!bRet) {
156            bRet = pFormat->FormatDateTime(wsValue, wsFormat, wsOutput,
157                                           FX_DATETIMETYPE_Date);
158          }
159        }
160        break;
161      }
162      case FX_LOCALECATEGORY_Time: {
163        CFX_Unitime dt;
164        bRet =
165            pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time, dt);
166        if (!bRet) {
167          bRet = pFormat->FormatDateTime(wsValue, wsFormat, wsOutput,
168                                         FX_DATETIMETYPE_Time);
169        }
170        break;
171      }
172      case FX_LOCALECATEGORY_DateTime: {
173        CFX_Unitime dt;
174        bRet = pFormat->ParseDateTime(wsValue, wsFormat,
175                                      FX_DATETIMETYPE_DateTime, dt);
176        if (!bRet) {
177          bRet = pFormat->FormatDateTime(wsValue, wsFormat, wsOutput,
178                                         FX_DATETIMETYPE_DateTime);
179        }
180        break;
181      }
182      default:
183        bRet = false;
184        break;
185    }
186  }
187  if (bRet && pMatchFormat)
188    *pMatchFormat = wsPatterns[i - 1];
189
190  if (pLocale)
191    m_pLocaleMgr->SetDefLocale(locale);
192
193  return bRet;
194}
195
196CFX_WideString CXFA_LocaleValue::GetValue() const {
197  return m_wsValue;
198}
199uint32_t CXFA_LocaleValue::GetType() const {
200  return m_dwType;
201}
202void CXFA_LocaleValue::SetValue(const CFX_WideString& wsValue,
203                                uint32_t dwType) {
204  m_wsValue = wsValue;
205  m_dwType = dwType;
206}
207CFX_WideString CXFA_LocaleValue::GetText() const {
208  if (m_bValid && m_dwType == XFA_VT_TEXT) {
209    return m_wsValue;
210  }
211  return CFX_WideString();
212}
213FX_FLOAT CXFA_LocaleValue::GetNum() const {
214  if (m_bValid && (m_dwType == XFA_VT_BOOLEAN || m_dwType == XFA_VT_INTEGER ||
215                   m_dwType == XFA_VT_DECIMAL || m_dwType == XFA_VT_FLOAT)) {
216    int64_t nIntegral = 0;
217    uint32_t dwFractional = 0;
218    int32_t nExponent = 0;
219    int cc = 0;
220    bool bNegative = false, bExpSign = false;
221    const FX_WCHAR* str = m_wsValue.c_str();
222    int len = m_wsValue.GetLength();
223    while (FXSYS_iswspace(str[cc]) && cc < len) {
224      cc++;
225    }
226    if (cc >= len) {
227      return 0;
228    }
229    if (str[0] == '+') {
230      cc++;
231    } else if (str[0] == '-') {
232      bNegative = true;
233      cc++;
234    }
235    int nIntegralLen = 0;
236    while (cc < len) {
237      if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc]) ||
238          nIntegralLen > 17) {
239        break;
240      }
241      nIntegral = nIntegral * 10 + str[cc] - '0';
242      cc++;
243      nIntegralLen++;
244    }
245    nIntegral = bNegative ? -nIntegral : nIntegral;
246    int scale = 0;
247    double fraction = 0.0;
248    if (cc < len && str[cc] == '.') {
249      cc++;
250      while (cc < len) {
251        fraction += fraction_scales[scale] * (str[cc] - '0');
252        scale++;
253        cc++;
254        if (scale == sizeof fraction_scales / sizeof(double) ||
255            !FXSYS_isDecimalDigit(str[cc])) {
256          break;
257        }
258      }
259      dwFractional = (uint32_t)(fraction * 4294967296.0);
260    }
261    if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) {
262      cc++;
263      if (cc < len) {
264        if (str[cc] == '+') {
265          cc++;
266        } else if (str[cc] == '-') {
267          bExpSign = true;
268          cc++;
269        }
270      }
271      while (cc < len) {
272        if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc])) {
273          break;
274        }
275        nExponent = nExponent * 10 + str[cc] - '0';
276        cc++;
277      }
278      nExponent = bExpSign ? -nExponent : nExponent;
279    }
280    FX_FLOAT fValue = (FX_FLOAT)(dwFractional / 4294967296.0);
281    fValue = nIntegral + (nIntegral >= 0 ? fValue : -fValue);
282    if (nExponent != 0) {
283      fValue *= FXSYS_pow(10, (FX_FLOAT)nExponent);
284    }
285    return fValue;
286  }
287  return 0;
288}
289FX_DOUBLE CXFA_LocaleValue::GetDoubleNum() const {
290  if (m_bValid && (m_dwType == XFA_VT_BOOLEAN || m_dwType == XFA_VT_INTEGER ||
291                   m_dwType == XFA_VT_DECIMAL || m_dwType == XFA_VT_FLOAT)) {
292    int64_t nIntegral = 0;
293    uint32_t dwFractional = 0;
294    int32_t nExponent = 0;
295    int32_t cc = 0;
296    bool bNegative = false, bExpSign = false;
297    const FX_WCHAR* str = m_wsValue.c_str();
298    int len = m_wsValue.GetLength();
299    while (FXSYS_iswspace(str[cc]) && cc < len) {
300      cc++;
301    }
302    if (cc >= len) {
303      return 0;
304    }
305    if (str[0] == '+') {
306      cc++;
307    } else if (str[0] == '-') {
308      bNegative = true;
309      cc++;
310    }
311    int32_t nIntegralLen = 0;
312    while (cc < len) {
313      if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc]) ||
314          nIntegralLen > 17) {
315        break;
316      }
317      nIntegral = nIntegral * 10 + str[cc] - '0';
318      cc++;
319      nIntegralLen++;
320    }
321    nIntegral = bNegative ? -nIntegral : nIntegral;
322    int32_t scale = 0;
323    FX_DOUBLE fraction = 0.0;
324    if (cc < len && str[cc] == '.') {
325      cc++;
326      while (cc < len) {
327        fraction += fraction_scales[scale] * (str[cc] - '0');
328        scale++;
329        cc++;
330        if (scale == sizeof fraction_scales / sizeof(FX_DOUBLE) ||
331            !FXSYS_isDecimalDigit(str[cc])) {
332          break;
333        }
334      }
335      dwFractional = (uint32_t)(fraction * 4294967296.0);
336    }
337    if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) {
338      cc++;
339      if (cc < len) {
340        if (str[cc] == '+') {
341          cc++;
342        } else if (str[cc] == '-') {
343          bExpSign = true;
344          cc++;
345        }
346      }
347      while (cc < len) {
348        if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc])) {
349          break;
350        }
351        nExponent = nExponent * 10 + str[cc] - '0';
352        cc++;
353      }
354      nExponent = bExpSign ? -nExponent : nExponent;
355    }
356    FX_DOUBLE dValue = (dwFractional / 4294967296.0);
357    dValue = nIntegral + (nIntegral >= 0 ? dValue : -dValue);
358    if (nExponent != 0) {
359      dValue *= FXSYS_pow(10, (FX_FLOAT)nExponent);
360    }
361    return dValue;
362  }
363  return 0;
364}
365CFX_Unitime CXFA_LocaleValue::GetDate() const {
366  if (m_bValid && m_dwType == XFA_VT_DATE) {
367    CFX_Unitime dt;
368    FX_DateFromCanonical(m_wsValue, dt);
369    return dt;
370  }
371  return CFX_Unitime();
372}
373CFX_Unitime CXFA_LocaleValue::GetTime() const {
374  if (m_bValid && m_dwType == XFA_VT_TIME) {
375    CFX_Unitime dt(0);
376    ASSERT(m_pLocaleMgr);
377    FX_TimeFromCanonical(m_wsValue.AsStringC(), dt,
378                         m_pLocaleMgr->GetDefLocale());
379    return dt;
380  }
381  return CFX_Unitime();
382}
383CFX_Unitime CXFA_LocaleValue::GetDateTime() const {
384  if (m_bValid && m_dwType == XFA_VT_DATETIME) {
385    int32_t index = m_wsValue.Find('T');
386    CFX_Unitime dt;
387    FX_DateFromCanonical(m_wsValue.Left(index), dt);
388    ASSERT(m_pLocaleMgr);
389    FX_TimeFromCanonical(
390        m_wsValue.Right(m_wsValue.GetLength() - index - 1).AsStringC(), dt,
391        m_pLocaleMgr->GetDefLocale());
392    return dt;
393  }
394  return CFX_Unitime();
395}
396bool CXFA_LocaleValue::SetText(const CFX_WideString& wsText) {
397  m_dwType = XFA_VT_TEXT;
398  m_wsValue = wsText;
399  return true;
400}
401bool CXFA_LocaleValue::SetText(const CFX_WideString& wsText,
402                               const CFX_WideString& wsFormat,
403                               IFX_Locale* pLocale) {
404  m_dwType = XFA_VT_TEXT;
405  return m_bValid = ParsePatternValue(wsText, wsFormat, pLocale);
406}
407bool CXFA_LocaleValue::SetNum(FX_FLOAT fNum) {
408  m_dwType = XFA_VT_FLOAT;
409  m_wsValue.Format(L"%.8g", (FX_DOUBLE)fNum);
410  return true;
411}
412bool CXFA_LocaleValue::SetNum(const CFX_WideString& wsNum,
413                              const CFX_WideString& wsFormat,
414                              IFX_Locale* pLocale) {
415  m_dwType = XFA_VT_FLOAT;
416  return m_bValid = ParsePatternValue(wsNum, wsFormat, pLocale);
417}
418bool CXFA_LocaleValue::SetDate(const CFX_Unitime& d) {
419  m_dwType = XFA_VT_DATE;
420  m_wsValue.Format(L"%04d-%02d-%02d", d.GetYear(), d.GetMonth(), d.GetDay());
421  return true;
422}
423bool CXFA_LocaleValue::SetDate(const CFX_WideString& wsDate,
424                               const CFX_WideString& wsFormat,
425                               IFX_Locale* pLocale) {
426  m_dwType = XFA_VT_DATE;
427  return m_bValid = ParsePatternValue(wsDate, wsFormat, pLocale);
428}
429bool CXFA_LocaleValue::SetTime(const CFX_Unitime& t) {
430  m_dwType = XFA_VT_TIME;
431  m_wsValue.Format(L"%02d:%02d:%02d", t.GetHour(), t.GetMinute(),
432                   t.GetSecond());
433  if (t.GetMillisecond() > 0) {
434    CFX_WideString wsTemp;
435    wsTemp.Format(L"%:03d", t.GetMillisecond());
436    m_wsValue += wsTemp;
437  }
438  return true;
439}
440bool CXFA_LocaleValue::SetTime(const CFX_WideString& wsTime,
441                               const CFX_WideString& wsFormat,
442                               IFX_Locale* pLocale) {
443  m_dwType = XFA_VT_TIME;
444  return m_bValid = ParsePatternValue(wsTime, wsFormat, pLocale);
445}
446bool CXFA_LocaleValue::SetDateTime(const CFX_Unitime& dt) {
447  m_dwType = XFA_VT_DATETIME;
448  m_wsValue.Format(L"%04d-%02d-%02dT%02d:%02d:%02d", dt.GetYear(),
449                   dt.GetMonth(), dt.GetDay(), dt.GetHour(), dt.GetMinute(),
450                   dt.GetSecond());
451  if (dt.GetMillisecond() > 0) {
452    CFX_WideString wsTemp;
453    wsTemp.Format(L"%:03d", dt.GetMillisecond());
454    m_wsValue += wsTemp;
455  }
456  return true;
457}
458bool CXFA_LocaleValue::SetDateTime(const CFX_WideString& wsDateTime,
459                                   const CFX_WideString& wsFormat,
460                                   IFX_Locale* pLocale) {
461  m_dwType = XFA_VT_DATETIME;
462  return m_bValid = ParsePatternValue(wsDateTime, wsFormat, pLocale);
463}
464
465bool CXFA_LocaleValue::FormatPatterns(CFX_WideString& wsResult,
466                                      const CFX_WideString& wsFormat,
467                                      IFX_Locale* pLocale,
468                                      XFA_VALUEPICTURE eValueType) const {
469  auto pFormat = pdfium::MakeUnique<CFX_FormatString>(m_pLocaleMgr, false);
470  std::vector<CFX_WideString> wsPatterns;
471  pFormat->SplitFormatString(wsFormat, wsPatterns);
472  wsResult.clear();
473  int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
474  for (int32_t i = 0; i < iCount; i++) {
475    if (FormatSinglePattern(wsResult, wsPatterns[i], pLocale, eValueType))
476      return true;
477  }
478  return false;
479}
480
481bool CXFA_LocaleValue::FormatSinglePattern(CFX_WideString& wsResult,
482                                           const CFX_WideString& wsFormat,
483                                           IFX_Locale* pLocale,
484                                           XFA_VALUEPICTURE eValueType) const {
485  IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
486  if (pLocale)
487    m_pLocaleMgr->SetDefLocale(pLocale);
488
489  wsResult.clear();
490  bool bRet = false;
491  auto pFormat = pdfium::MakeUnique<CFX_FormatString>(m_pLocaleMgr, false);
492  FX_LOCALECATEGORY eCategory = pFormat->GetCategory(wsFormat);
493  eCategory = XFA_ValugeCategory(eCategory, m_dwType);
494  switch (eCategory) {
495    case FX_LOCALECATEGORY_Null:
496      if (m_wsValue.IsEmpty()) {
497        bRet = pFormat->FormatNull(wsFormat, wsResult);
498      }
499      break;
500    case FX_LOCALECATEGORY_Zero:
501      if (m_wsValue == L"0") {
502        bRet = pFormat->FormatZero(wsFormat, wsResult);
503      }
504      break;
505    case FX_LOCALECATEGORY_Num:
506      bRet = pFormat->FormatNum(m_wsValue, wsFormat, wsResult);
507      break;
508    case FX_LOCALECATEGORY_Text:
509      bRet = pFormat->FormatText(m_wsValue, wsFormat, wsResult);
510      break;
511    case FX_LOCALECATEGORY_Date:
512      bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, wsResult,
513                                     FX_DATETIMETYPE_Date);
514      break;
515    case FX_LOCALECATEGORY_Time:
516      bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, wsResult,
517                                     FX_DATETIMETYPE_Time);
518      break;
519    case FX_LOCALECATEGORY_DateTime:
520      bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, wsResult,
521                                     FX_DATETIMETYPE_DateTime);
522      break;
523    default:
524      wsResult = m_wsValue;
525      bRet = true;
526  }
527  if (!bRet && (eCategory != FX_LOCALECATEGORY_Num ||
528                eValueType != XFA_VALUEPICTURE_Display)) {
529    wsResult = m_wsValue;
530  }
531  if (pLocale)
532    m_pLocaleMgr->SetDefLocale(locale);
533
534  return bRet;
535}
536
537static bool XFA_ValueSplitDateTime(const CFX_WideString& wsDateTime,
538                                   CFX_WideString& wsDate,
539                                   CFX_WideString& wsTime) {
540  wsDate = L"";
541  wsTime = L"";
542  if (wsDateTime.IsEmpty()) {
543    return false;
544  }
545  int nSplitIndex = -1;
546  nSplitIndex = wsDateTime.Find('T');
547  if (nSplitIndex < 0) {
548    nSplitIndex = wsDateTime.Find(' ');
549  }
550  if (nSplitIndex < 0) {
551    return false;
552  }
553  wsDate = wsDateTime.Left(nSplitIndex);
554  wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex - 1);
555  return true;
556}
557bool CXFA_LocaleValue::ValidateCanonicalValue(const CFX_WideString& wsValue,
558                                              uint32_t dwVType) {
559  if (wsValue.IsEmpty()) {
560    return true;
561  }
562  CFX_Unitime dt;
563  switch (dwVType) {
564    case XFA_VT_DATE: {
565      if (ValidateCanonicalDate(wsValue, dt)) {
566        return true;
567      }
568      CFX_WideString wsDate, wsTime;
569      if (XFA_ValueSplitDateTime(wsValue, wsDate, wsTime) &&
570          ValidateCanonicalDate(wsDate, dt)) {
571        return true;
572      }
573      return false;
574    }
575    case XFA_VT_TIME: {
576      if (ValidateCanonicalTime(wsValue)) {
577        return true;
578      }
579      CFX_WideString wsDate, wsTime;
580      if (XFA_ValueSplitDateTime(wsValue, wsDate, wsTime) &&
581          ValidateCanonicalTime(wsTime)) {
582        return true;
583      }
584      return false;
585    }
586    case XFA_VT_DATETIME: {
587      CFX_WideString wsDate, wsTime;
588      if (XFA_ValueSplitDateTime(wsValue, wsDate, wsTime) &&
589          ValidateCanonicalDate(wsDate, dt) && ValidateCanonicalTime(wsTime)) {
590        return true;
591      }
592    } break;
593  }
594  return true;
595}
596bool CXFA_LocaleValue::ValidateCanonicalDate(const CFX_WideString& wsDate,
597                                             CFX_Unitime& unDate) {
598  const uint16_t LastDay[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
599  const uint16_t wCountY = 4, wCountM = 2, wCountD = 2;
600  int nLen = wsDate.GetLength();
601  if (nLen < wCountY || nLen > wCountY + wCountM + wCountD + 2) {
602    return false;
603  }
604  const bool bSymbol = wsDate.Find(0x2D) != -1;
605  uint16_t wYear = 0;
606  uint16_t wMonth = 0;
607  uint16_t wDay = 0;
608  const FX_WCHAR* pDate = wsDate.c_str();
609  int nIndex = 0, nStart = 0;
610  while (pDate[nIndex] != '\0' && nIndex < wCountY) {
611    if (!FXSYS_isDecimalDigit(pDate[nIndex])) {
612      return false;
613    }
614    wYear = (pDate[nIndex] - '0') + wYear * 10;
615    nIndex++;
616  }
617  if (bSymbol) {
618    if (pDate[nIndex] != 0x2D) {
619      return false;
620    }
621    nIndex++;
622  }
623  nStart = nIndex;
624  while (pDate[nIndex] != '\0' && nIndex - nStart < wCountM && nIndex < nLen) {
625    if (!FXSYS_isDecimalDigit(pDate[nIndex])) {
626      return false;
627    }
628    wMonth = (pDate[nIndex] - '0') + wMonth * 10;
629    nIndex++;
630  }
631  if (bSymbol) {
632    if (pDate[nIndex] != 0x2D) {
633      return false;
634    }
635    nIndex++;
636  }
637  nStart = nIndex;
638  while (pDate[nIndex] != '\0' && nIndex - nStart < wCountD && nIndex < nLen) {
639    if (!FXSYS_isDecimalDigit(pDate[nIndex])) {
640      return false;
641    }
642    wDay = (pDate[nIndex] - '0') + wDay * 10;
643    nIndex++;
644  }
645  if (nIndex != nLen) {
646    return false;
647  }
648  if (wYear < 1900 || wYear > 2029) {
649    return false;
650  }
651  if (wMonth < 1 || wMonth > 12) {
652    if (wMonth == 0 && nLen == wCountY) {
653      return true;
654    }
655    return false;
656  }
657  if (wDay < 1) {
658    if (wDay == 0 && (nLen == wCountY + wCountM)) {
659      return true;
660    }
661    return false;
662  }
663  if (wMonth == 2) {
664    if (wYear % 400 == 0 || (wYear % 100 != 0 && wYear % 4 == 0)) {
665      if (wDay > 29) {
666        return false;
667      }
668    } else {
669      if (wDay > 28) {
670        return false;
671      }
672    }
673  } else if (wDay > LastDay[wMonth - 1]) {
674    return false;
675  }
676  CFX_Unitime ut;
677  ut.Set(wYear, static_cast<uint8_t>(wMonth), static_cast<uint8_t>(wDay));
678  unDate = unDate + ut;
679  return true;
680}
681bool CXFA_LocaleValue::ValidateCanonicalTime(const CFX_WideString& wsTime) {
682  int nLen = wsTime.GetLength();
683  if (nLen < 2)
684    return false;
685  const uint16_t wCountH = 2;
686  const uint16_t wCountM = 2;
687  const uint16_t wCountS = 2;
688  const uint16_t wCountF = 3;
689  const bool bSymbol = wsTime.Find(':') != -1;
690  uint16_t wHour = 0;
691  uint16_t wMinute = 0;
692  uint16_t wSecond = 0;
693  uint16_t wFraction = 0;
694  const FX_WCHAR* pTime = wsTime.c_str();
695  int nIndex = 0;
696  int nStart = 0;
697  while (nIndex - nStart < wCountH && pTime[nIndex]) {
698    if (!FXSYS_isDecimalDigit(pTime[nIndex]))
699      return false;
700    wHour = pTime[nIndex] - '0' + wHour * 10;
701    nIndex++;
702  }
703  if (bSymbol) {
704    if (nIndex < nLen && pTime[nIndex] != ':')
705      return false;
706    nIndex++;
707  }
708  nStart = nIndex;
709  while (nIndex - nStart < wCountM && nIndex < nLen && pTime[nIndex]) {
710    if (!FXSYS_isDecimalDigit(pTime[nIndex]))
711      return false;
712    wMinute = pTime[nIndex] - '0' + wMinute * 10;
713    nIndex++;
714  }
715  if (bSymbol) {
716    if (nIndex < nLen && pTime[nIndex] != ':')
717      return false;
718    nIndex++;
719  }
720  nStart = nIndex;
721  while (nIndex - nStart < wCountS && nIndex < nLen && pTime[nIndex]) {
722    if (!FXSYS_isDecimalDigit(pTime[nIndex]))
723      return false;
724    wSecond = pTime[nIndex] - '0' + wSecond * 10;
725    nIndex++;
726  }
727  if (wsTime.Find('.') > 0) {
728    if (pTime[nIndex] != '.')
729      return false;
730    nIndex++;
731    nStart = nIndex;
732    while (nIndex - nStart < wCountF && nIndex < nLen && pTime[nIndex]) {
733      if (!FXSYS_isDecimalDigit(pTime[nIndex]))
734        return false;
735      wFraction = pTime[nIndex] - '0' + wFraction * 10;
736      nIndex++;
737    }
738  }
739  if (nIndex < nLen) {
740    if (pTime[nIndex] == 'Z') {
741      nIndex++;
742    } else if (pTime[nIndex] == '-' || pTime[nIndex] == '+') {
743      int16_t nOffsetH = 0;
744      int16_t nOffsetM = 0;
745      nIndex++;
746      nStart = nIndex;
747      while (nIndex - nStart < wCountH && nIndex < nLen && pTime[nIndex]) {
748        if (!FXSYS_isDecimalDigit(pTime[nIndex]))
749          return false;
750        nOffsetH = pTime[nIndex] - '0' + nOffsetH * 10;
751        nIndex++;
752      }
753      if (bSymbol) {
754        if (nIndex < nLen && pTime[nIndex] != ':')
755          return false;
756        nIndex++;
757      }
758      nStart = nIndex;
759      while (nIndex - nStart < wCountM && nIndex < nLen && pTime[nIndex]) {
760        if (!FXSYS_isDecimalDigit(pTime[nIndex]))
761          return false;
762        nOffsetM = pTime[nIndex] - '0' + nOffsetM * 10;
763        nIndex++;
764      }
765      if (nOffsetH > 12 || nOffsetM >= 60)
766        return false;
767    }
768  }
769  return nIndex == nLen && wHour < 24 && wMinute < 60 && wSecond < 60 &&
770         wFraction <= 999;
771}
772bool CXFA_LocaleValue::ValidateCanonicalDateTime(
773    const CFX_WideString& wsDateTime) {
774  CFX_WideString wsDate, wsTime;
775  if (wsDateTime.IsEmpty()) {
776    return false;
777  }
778  int nSplitIndex = -1;
779  nSplitIndex = wsDateTime.Find('T');
780  if (nSplitIndex < 0) {
781    nSplitIndex = wsDateTime.Find(' ');
782  }
783  if (nSplitIndex < 0) {
784    return false;
785  }
786  wsDate = wsDateTime.Left(nSplitIndex);
787  wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex - 1);
788  CFX_Unitime dt;
789  return ValidateCanonicalDate(wsDate, dt) && ValidateCanonicalTime(wsTime);
790}
791bool CXFA_LocaleValue::ParsePatternValue(const CFX_WideString& wsValue,
792                                         const CFX_WideString& wsPattern,
793                                         IFX_Locale* pLocale) {
794  IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
795  if (pLocale)
796    m_pLocaleMgr->SetDefLocale(pLocale);
797
798  auto pFormat = pdfium::MakeUnique<CFX_FormatString>(m_pLocaleMgr, false);
799  std::vector<CFX_WideString> wsPatterns;
800  pFormat->SplitFormatString(wsPattern, wsPatterns);
801  bool bRet = false;
802  int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
803  for (int32_t i = 0; i < iCount && !bRet; i++) {
804    CFX_WideString wsFormat = wsPatterns[i];
805    FX_LOCALECATEGORY eCategory = pFormat->GetCategory(wsFormat);
806    eCategory = XFA_ValugeCategory(eCategory, m_dwType);
807    switch (eCategory) {
808      case FX_LOCALECATEGORY_Null:
809        bRet = pFormat->ParseNull(wsValue, wsFormat);
810        if (bRet) {
811          m_wsValue.clear();
812        }
813        break;
814      case FX_LOCALECATEGORY_Zero:
815        bRet = pFormat->ParseZero(wsValue, wsFormat);
816        if (bRet)
817          m_wsValue = L"0";
818        break;
819      case FX_LOCALECATEGORY_Num: {
820        CFX_WideString fNum;
821        bRet = pFormat->ParseNum(wsValue, wsFormat, fNum);
822        if (bRet) {
823          m_wsValue = fNum;
824        }
825        break;
826      }
827      case FX_LOCALECATEGORY_Text:
828        bRet = pFormat->ParseText(wsValue, wsFormat, m_wsValue);
829        break;
830      case FX_LOCALECATEGORY_Date: {
831        CFX_Unitime dt;
832        bRet = ValidateCanonicalDate(wsValue, dt);
833        if (!bRet) {
834          bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date,
835                                        dt);
836        }
837        if (bRet) {
838          SetDate(dt);
839        }
840        break;
841      }
842      case FX_LOCALECATEGORY_Time: {
843        CFX_Unitime dt;
844        bRet =
845            pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time, dt);
846        if (bRet) {
847          SetTime(dt);
848        }
849        break;
850      }
851      case FX_LOCALECATEGORY_DateTime: {
852        CFX_Unitime dt;
853        bRet = pFormat->ParseDateTime(wsValue, wsFormat,
854                                      FX_DATETIMETYPE_DateTime, dt);
855        if (bRet) {
856          SetDateTime(dt);
857        }
858        break;
859      }
860      default:
861        m_wsValue = wsValue;
862        bRet = true;
863        break;
864    }
865  }
866  if (!bRet)
867    m_wsValue = wsValue;
868
869  if (pLocale)
870    m_pLocaleMgr->SetDefLocale(locale);
871
872  return bRet;
873}
874
875void CXFA_LocaleValue::GetNumbericFormat(CFX_WideString& wsFormat,
876                                         int32_t nIntLen,
877                                         int32_t nDecLen,
878                                         bool bSign) {
879  ASSERT(wsFormat.IsEmpty());
880  ASSERT(nIntLen >= -1 && nDecLen >= -1);
881  int32_t nTotalLen = (nIntLen >= 0 ? nIntLen : 2) + (bSign ? 1 : 0) +
882                      (nDecLen >= 0 ? nDecLen : 2) + (nDecLen == 0 ? 0 : 1);
883  FX_WCHAR* lpBuf = wsFormat.GetBuffer(nTotalLen);
884  int32_t nPos = 0;
885  if (bSign) {
886    lpBuf[nPos++] = L's';
887  }
888  if (nIntLen == -1) {
889    lpBuf[nPos++] = L'z';
890    lpBuf[nPos++] = L'*';
891  } else {
892    while (nIntLen) {
893      lpBuf[nPos++] = L'z';
894      nIntLen--;
895    }
896  }
897  if (nDecLen != 0) {
898    lpBuf[nPos++] = L'.';
899  }
900  if (nDecLen == -1) {
901    lpBuf[nPos++] = L'z';
902    lpBuf[nPos++] = L'*';
903  } else {
904    while (nDecLen) {
905      lpBuf[nPos++] = L'z';
906      nDecLen--;
907    }
908  }
909  wsFormat.ReleaseBuffer(nTotalLen);
910}
911bool CXFA_LocaleValue::ValidateNumericTemp(CFX_WideString& wsNumeric,
912                                           CFX_WideString& wsFormat,
913                                           IFX_Locale* pLocale,
914                                           int32_t* pos) {
915  if (wsFormat.IsEmpty() || wsNumeric.IsEmpty()) {
916    return true;
917  }
918  const FX_WCHAR* pNum = wsNumeric.c_str();
919  const FX_WCHAR* pFmt = wsFormat.c_str();
920  int32_t n = 0, nf = 0;
921  FX_WCHAR c = pNum[n];
922  FX_WCHAR cf = pFmt[nf];
923  if (cf == L's') {
924    if (c == L'-' || c == L'+') {
925      ++n;
926    }
927    ++nf;
928  }
929  bool bLimit = true;
930  int32_t nCount = wsNumeric.GetLength();
931  int32_t nCountFmt = wsFormat.GetLength();
932  while (n < nCount && (bLimit ? nf < nCountFmt : true) &&
933         FXSYS_isDecimalDigit(c = pNum[n])) {
934    if (bLimit == true) {
935      if ((cf = pFmt[nf]) == L'*') {
936        bLimit = false;
937      } else if (cf == L'z') {
938        nf++;
939      } else {
940        return false;
941      }
942    }
943    n++;
944  }
945  if (n == nCount) {
946    return true;
947  }
948  if (nf == nCountFmt) {
949    return false;
950  }
951  while (nf < nCountFmt && (cf = pFmt[nf]) != L'.') {
952    ASSERT(cf == L'z' || cf == L'*');
953    ++nf;
954  }
955  CFX_WideString wsDecimalSymbol;
956  if (pLocale) {
957    pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsDecimalSymbol);
958  } else {
959    wsDecimalSymbol = CFX_WideString(L'.');
960  }
961  if (pFmt[nf] != L'.') {
962    return false;
963  }
964  if (wsDecimalSymbol != CFX_WideStringC(c) && c != L'.') {
965    return false;
966  }
967  ++nf;
968  ++n;
969  bLimit = true;
970  while (n < nCount && (bLimit ? nf < nCountFmt : true) &&
971         FXSYS_isDecimalDigit(c = pNum[n])) {
972    if (bLimit == true) {
973      if ((cf = pFmt[nf]) == L'*') {
974        bLimit = false;
975      } else if (cf == L'z') {
976        nf++;
977      } else {
978        return false;
979      }
980    }
981    n++;
982  }
983  return n == nCount;
984}
985