• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ValueCategory(FX_LOCALECATEGORY eCategory,uint32_t dwValueType)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 
ValueSplitDateTime(const WideString & wsDateTime,WideString & wsDate,WideString & wsTime)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 
CXFA_LocaleValue()65 CXFA_LocaleValue::CXFA_LocaleValue()
66     : m_pLocaleMgr(nullptr), m_dwType(XFA_VT_NULL), m_bValid(true) {}
67 
CXFA_LocaleValue(const CXFA_LocaleValue & value)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 
CXFA_LocaleValue(uint32_t dwType,CXFA_LocaleMgr * pLocaleMgr)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 
CXFA_LocaleValue(uint32_t dwType,const WideString & wsValue,CXFA_LocaleMgr * pLocaleMgr)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 
CXFA_LocaleValue(uint32_t dwType,const WideString & wsValue,const WideString & wsFormat,IFX_Locale * pLocale,CXFA_LocaleMgr * pLocaleMgr)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 
operator =(const CXFA_LocaleValue & value)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 
~CXFA_LocaleValue()104 CXFA_LocaleValue::~CXFA_LocaleValue() {}
105 
ValidateValue(const WideString & wsValue,const WideString & wsPattern,IFX_Locale * pLocale,WideString * pMatchFormat)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 
GetDoubleNum() const194 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 
GetDate() const274 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 
GetTime() const283 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 
SetDate(const CFX_DateTime & d)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 
SetTime(const CFX_DateTime & t)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 
SetDateTime(const CFX_DateTime & dt)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 
FormatPatterns(WideString & wsResult,const WideString & wsFormat,IFX_Locale * pLocale,XFA_VALUEPICTURE eValueType) const319 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 
FormatSinglePattern(WideString & wsResult,const WideString & wsFormat,IFX_Locale * pLocale,XFA_VALUEPICTURE eValueType) const335 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 
ValidateCanonicalValue(const WideString & wsValue,uint32_t dwVType)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 
ValidateCanonicalDate(const WideString & wsDate,CFX_DateTime * unDate)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 
ValidateCanonicalTime(const WideString & wsTime)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 
ParsePatternValue(const WideString & wsValue,const WideString & wsPattern,IFX_Locale * pLocale)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 
GetNumericFormat(WideString & wsFormat,int32_t nIntLen,int32_t nDecLen)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 
ValidateNumericTemp(const WideString & wsNumeric,const WideString & wsFormat,IFX_Locale * pLocale)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