7#include "xfa/fxfa/parser/cxfa_localevalue.h"
15#include "core/fxcrt/cfx_datetime.h"
16#include "core/fxcrt/fx_extension.h"
17#include "third_party/base/check.h"
18#include "third_party/base/containers/span.h"
19#include "xfa/fgas/crt/cfgas_stringformatter.h"
20#include "xfa/fxfa/parser/cxfa_document.h"
21#include "xfa/fxfa/parser/cxfa_localemgr.h"
22#include "xfa/fxfa/parser/xfa_utils.h"
51bool ValueSplitDateTime(
const WideString& wsDateTime,
59 auto nSplitIndex = wsDateTime.Find(
'T');
60 if (!nSplitIndex.has_value())
61 nSplitIndex = wsDateTime.Find(
' ');
62 if (!nSplitIndex.has_value())
65 wsDate = wsDateTime.First(nSplitIndex.value());
66 wsTime = wsDateTime.Last(wsDateTime.GetLength() - nSplitIndex.value() - 1);
71 CPPGC_STACK_ALLOCATED();
75 : m_pLocaleMgr(pLocaleMgr),
76 m_pNewLocale(pNewLocale),
77 m_pOrigLocale(pNewLocale ? m_pLocaleMgr->GetDefLocale() :
nullptr) {
79 m_pLocaleMgr->SetDefLocale(pNewLocale);
84 m_pLocaleMgr->SetDefLocale(m_pOrigLocale);
87 ScopedLocale(
const ScopedLocale& that) =
delete;
88 ScopedLocale& operator=(
const ScopedLocale& that) =
delete;
106 const WideString& wsValue,
107 CXFA_LocaleMgr* pLocaleMgr)
111 m_bValid(ValidateCanonicalValue(wsValue, eType)) {}
114 const WideString& wsValue,
115 const WideString& wsFormat,
117 CXFA_LocaleMgr* pLocaleMgr)
120 m_bValid(ParsePatternValue(wsValue, wsFormat, pLocale)) {}
130 const WideString& wsPattern,
132 WideString* pMatchFormat) {
136 ScopedLocale scoped_locale(m_pLocaleMgr, pLocale);
137 std::vector<WideString> wsPatterns =
138 CFGAS_StringFormatter::SplitOnBars(wsPattern);
143 for (; !bRet && i < wsPatterns.size(); i++) {
144 const WideString& wsFormat = wsPatterns[i];
146 switch (ValueCategory(pFormat->GetCategory(), m_eType)) {
148 bRet = pFormat->ParseNull(wsValue);
153 bRet = pFormat->ParseZero(wsValue);
159 bRet = pFormat->ParseNum(m_pLocaleMgr, wsValue, &fNum);
161 bRet = pFormat->FormatNum(m_pLocaleMgr, wsValue, &wsOutput);
165 bRet = pFormat->ParseText(wsValue, &wsOutput);
168 bRet = pFormat->FormatText(wsValue, &wsOutput);
172 bRet = ValidateCanonicalDate(wsValue, &dt);
174 bRet = pFormat->ParseDateTime(
175 m_pLocaleMgr, wsValue, CFGAS_StringFormatter::DateTimeType::kDate,
178 bRet = pFormat->FormatDateTime(
179 m_pLocaleMgr, wsValue,
180 CFGAS_StringFormatter::DateTimeType::kDate, &wsOutput);
187 bRet = pFormat->ParseDateTime(
188 m_pLocaleMgr, wsValue, CFGAS_StringFormatter::DateTimeType::kTime,
191 bRet = pFormat->FormatDateTime(
192 m_pLocaleMgr, wsValue, CFGAS_StringFormatter::DateTimeType::kTime,
199 bRet = pFormat->ParseDateTime(
200 m_pLocaleMgr, wsValue,
201 CFGAS_StringFormatter::DateTimeType::kDateTime, &dt);
203 bRet = pFormat->FormatDateTime(
204 m_pLocaleMgr, wsValue,
205 CFGAS_StringFormatter::DateTimeType::kDateTime, &wsOutput);
214 if (bRet && pMatchFormat)
215 *pMatchFormat = wsPatterns[i - 1];
227 return wcstod(m_wsValue.c_str(),
nullptr);
235 FX_DateFromCanonical(m_wsValue.span(), &dt);
244 FX_TimeFromCanonical(m_pLocaleMgr->GetDefLocale(), m_wsValue.span(), &dt);
250 m_wsValue = WideString::Format(L"%04d-%02d-%02d", d.GetYear(), d.GetMonth(),
257 m_wsValue = WideString::Format(L"%02d:%02d:%02d", t.GetHour(), t.GetMinute(),
259 if (t.GetMillisecond() > 0)
260 m_wsValue += WideString::Format(L"%:03d", t.GetMillisecond());
266 m_wsValue = WideString::Format(L"%04d-%02d-%02dT%02d:%02d:%02d", dt.GetYear(),
267 dt.GetMonth(), dt.GetDay(), dt.GetHour(),
268 dt.GetMinute(), dt.GetSecond());
269 if (dt.GetMillisecond() > 0)
270 m_wsValue += WideString::Format(L"%:03d", dt.GetMillisecond());
275 const WideString& wsFormat,
279 for (
const auto& pattern : CFGAS_StringFormatter::SplitOnBars(wsFormat)) {
280 if (FormatSinglePattern(wsResult, pattern, pLocale, eValueType))
287 const WideString& wsFormat,
293 ScopedLocale scoped_locale(m_pLocaleMgr, pLocale);
299 ValueCategory(pFormat->GetCategory(), m_eType);
302 if (m_wsValue.IsEmpty())
303 bRet = pFormat->FormatNull(&wsResult);
306 if (m_wsValue.EqualsASCII(
"0"))
307 bRet = pFormat->FormatZero(&wsResult);
309 case CFGAS_StringFormatter::Category::kNum:
310 bRet = pFormat->FormatNum(m_pLocaleMgr, m_wsValue, &wsResult);
312 case CFGAS_StringFormatter::Category::kText:
313 bRet = pFormat->FormatText(m_wsValue, &wsResult);
315 case CFGAS_StringFormatter::Category::kDate:
316 bRet = pFormat->FormatDateTime(m_pLocaleMgr, m_wsValue,
317 CFGAS_StringFormatter::DateTimeType::kDate,
320 case CFGAS_StringFormatter::Category::kTime:
321 bRet = pFormat->FormatDateTime(m_pLocaleMgr, m_wsValue,
322 CFGAS_StringFormatter::DateTimeType::kTime,
325 case CFGAS_StringFormatter::Category::kDateTime:
326 bRet = pFormat->FormatDateTime(
327 m_pLocaleMgr, m_wsValue,
328 CFGAS_StringFormatter::DateTimeType::kDateTime, &wsResult);
331 wsResult = m_wsValue;
336 wsResult = m_wsValue;
350 if (ValidateCanonicalDate(wsValue, &dt))
355 if (ValueSplitDateTime(wsValue, wsDate, wsTime) &&
356 ValidateCanonicalDate(wsDate, &dt)) {
362 if (ValidateCanonicalTime(wsValue))
367 if (ValueSplitDateTime(wsValue, wsDate, wsTime) &&
368 ValidateCanonicalTime(wsTime)) {
374 WideString wsDate, wsTime;
375 if (ValueSplitDateTime(wsValue, wsDate, wsTime) &&
376 ValidateCanonicalDate(wsDate, &dt) && ValidateCanonicalTime(wsTime)) {
389 static const uint8_t LastDay[12] = {31, 28, 31, 30, 31, 30,
390 31, 31, 30, 31, 30, 31};
391 static const uint16_t wCountY = 4;
392 static const uint16_t wCountM = 2;
393 static const uint16_t wCountD = 2;
394 pdfium::span<
const wchar_t> spDate = wsDate.span();
395 if (spDate.size() < wCountY ||
396 spDate.size() > wCountY + wCountM + wCountD + 2) {
399 const bool bSymbol = wsDate.Contains(0x2D);
405 while (nIndex < wCountY && spDate[nIndex] !=
'\0') {
406 if (!FXSYS_IsDecimalDigit(spDate[nIndex]))
409 wYear = (spDate[nIndex] -
'0') + wYear * 10;
413 if (nIndex >= spDate.size() || spDate[nIndex] != 0x2D)
419 while (nIndex < spDate.size() && spDate[nIndex] !=
'\0' &&
420 nIndex - nStart < wCountM) {
421 if (!FXSYS_IsDecimalDigit(spDate[nIndex]))
424 wMonth = (spDate[nIndex] -
'0') + wMonth * 10;
428 if (nIndex >= spDate.size() || spDate[nIndex] != 0x2D)
434 while (nIndex < spDate.size() && spDate[nIndex] !=
'\0' &&
435 nIndex - nStart < wCountD) {
436 if (!FXSYS_IsDecimalDigit(spDate[nIndex]))
439 wDay = (spDate[nIndex] -
'0') + wDay * 10;
442 if (nIndex != spDate.size())
444 if (wYear < 1900 || wYear > 2029)
446 if (wMonth < 1 || wMonth > 12)
447 return wMonth == 0 && spDate.size() == wCountY;
449 return wDay == 0 && spDate.size() == wCountY + wCountM;
451 if (wYear % 400 == 0 || (wYear % 100 != 0 && wYear % 4 == 0)) {
454 }
else if (wDay > 28) {
457 }
else if (wDay > LastDay[wMonth - 1]) {
462 static_cast<uint8_t>(wDay)
);
467 pdfium::span<
const wchar_t> spTime = wsTime.span();
468 if (spTime.size() < 2)
471 const uint16_t wCountH = 2;
472 const uint16_t wCountM = 2;
473 const uint16_t wCountS = 2;
474 const uint16_t wCountF = 3;
475 const bool bSymbol = wsTime.Contains(
':');
477 uint16_t wMinute = 0;
478 uint16_t wSecond = 0;
479 uint16_t wFraction = 0;
482 while (nIndex - nStart < wCountH && spTime[nIndex]) {
483 if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
485 wHour = spTime[nIndex] -
'0' + wHour * 10;
489 if (nIndex < spTime.size() && spTime[nIndex] !=
':')
495 while (nIndex < spTime.size() && spTime[nIndex] !=
'\0' &&
496 nIndex - nStart < wCountM) {
497 if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
499 wMinute = spTime[nIndex] -
'0' + wMinute * 10;
503 if (nIndex >= spTime.size() || spTime[nIndex] !=
':')
508 while (nIndex < spTime.size() && spTime[nIndex] !=
'\0' &&
509 nIndex - nStart < wCountS) {
510 if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
512 wSecond = spTime[nIndex] -
'0' + wSecond * 10;
515 auto pos = wsTime.Find(
'.');
516 if (pos.has_value() && pos.value() != 0) {
517 if (nIndex >= spTime.size() || spTime[nIndex] !=
'.')
521 while (nIndex < spTime.size() && spTime[nIndex] !=
'\0' &&
522 nIndex - nStart < wCountF) {
523 if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
525 wFraction = spTime[nIndex] -
'0' + wFraction * 10;
529 if (nIndex < spTime.size()) {
530 if (spTime[nIndex] ==
'Z') {
532 }
else if (spTime[nIndex] ==
'-' || spTime[nIndex] ==
'+') {
533 int16_t nOffsetH = 0;
534 int16_t nOffsetM = 0;
537 while (nIndex < spTime.size() && spTime[nIndex] !=
'\0' &&
538 nIndex - nStart < wCountH) {
539 if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
541 nOffsetH = spTime[nIndex] -
'0' + nOffsetH * 10;
545 if (nIndex >= spTime.size() || spTime[nIndex] !=
':')
550 while (nIndex < spTime.size() && spTime[nIndex] !=
'\0' &&
551 nIndex - nStart < wCountM) {
552 if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
554 nOffsetM = spTime[nIndex] -
'0' + nOffsetM * 10;
557 if (nOffsetH > 12 || nOffsetM >= 60)
561 return nIndex == spTime.size() && wHour < 24 && wMinute < 60 &&
562 wSecond < 60 && wFraction <= 999;
566 const WideString& wsPattern,
571 std::vector<WideString> wsPatterns =
572 CFGAS_StringFormatter::SplitOnBars(wsPattern);
574 ScopedLocale scoped_locale(m_pLocaleMgr, pLocale);
576 for (size_t i = 0; !bRet && i < wsPatterns.size(); i++) {
577 const WideString& wsFormat = wsPatterns[i];
579 switch (ValueCategory(pFormat->GetCategory(), m_eType)) {
581 bRet = pFormat->ParseNull(wsValue);
586 bRet = pFormat->ParseZero(wsValue);
592 bRet = pFormat->ParseNum(m_pLocaleMgr, wsValue, &fNum);
594 m_wsValue = std::move(fNum);
597 case CFGAS_StringFormatter::Category::kText:
598 bRet = pFormat->ParseText(wsValue, &m_wsValue);
602 bRet = ValidateCanonicalDate(wsValue, &dt);
604 bRet = pFormat->ParseDateTime(
605 m_pLocaleMgr, wsValue, CFGAS_StringFormatter::DateTimeType::kDate,
614 bRet = pFormat->ParseDateTime(
615 m_pLocaleMgr, wsValue, CFGAS_StringFormatter::DateTimeType::kTime,
623 bRet = pFormat->ParseDateTime(
624 m_pLocaleMgr, wsValue,
625 CFGAS_StringFormatter::DateTimeType::kDateTime, &dt);
645 DCHECK(wsFormat.IsEmpty());
646 DCHECK(nIntLen >= -1);
647 DCHECK(nDecLen >= -1);
649 int32_t nTotalLen = (nIntLen >= 0 ? nIntLen : 2) + 1 +
650 (nDecLen >= 0 ? nDecLen : 2) + (nDecLen == 0 ? 0 : 1);
653 pdfium::span<
wchar_t> lpBuf = wsFormat.GetBuffer(nTotalLen);
655 lpBuf[nPos++] = L's';
658 lpBuf[nPos++] = L'z';
659 lpBuf[nPos++] = L'*';
662 lpBuf[nPos++] = L'z';
667 lpBuf[nPos++] = L'.';
670 lpBuf[nPos++] = L'z';
671 lpBuf[nPos++] = L'*';
674 lpBuf[nPos++] = L'z';
679 wsFormat.ReleaseBuffer(nTotalLen);
683 const WideString& wsFormat,
688 pdfium::span<
const wchar_t> spNum = wsNumeric.span();
689 pdfium::span<
const wchar_t> spFmt = wsFormat.span();
692 wchar_t c = spNum[n];
693 wchar_t cf = spFmt[nf];
695 if (c == L'-' || c == L'+')
701 size_t nCount = wsNumeric.GetLength();
702 size_t nCountFmt = wsFormat.GetLength();
703 while (n < nCount && (!bLimit || nf < nCountFmt) &&
704 FXSYS_IsDecimalDigit(c = spNum[n])) {
706 if ((cf = spFmt[nf]) == L'*')
720 while (nf < nCountFmt && (cf = spFmt[nf]) != L'.') {
721 DCHECK(cf == L'z' || cf == L'*');
725 WideString wsDecimalSymbol;
729 wsDecimalSymbol
= WideString
(L'.'
);
731 if (spFmt[nf] != L'.')
733 if (wsDecimalSymbol != WideStringView(c) && c != L'.')
739 while (n < nCount && (!bLimit || nf < nCountFmt) &&
740 FXSYS_IsDecimalDigit(spNum[n])) {
742 if ((cf = spFmt[nf]) == L'*')
void SetDate(int32_t year, uint8_t month, uint8_t day)
CXFA_LocaleValue(ValueType eType, CXFA_LocaleMgr *pLocaleMgr)
bool SetDate(const CFX_DateTime &d)
CXFA_LocaleValue(ValueType dwType, const WideString &wsValue, const WideString &wsFormat, GCedLocaleIface *pLocale, CXFA_LocaleMgr *pLocaleMgr)
double GetDoubleNum() const
CFX_DateTime GetTime() const
CFX_DateTime GetDate() const
CXFA_LocaleValue(ValueType eType, const WideString &wsValue, CXFA_LocaleMgr *pLocaleMgr)
bool FormatPatterns(WideString &wsResult, const WideString &wsFormat, GCedLocaleIface *pLocale, XFA_ValuePicture eValueType) const
CXFA_LocaleValue & operator=(const CXFA_LocaleValue &that)
bool ValidateValue(const WideString &wsValue, const WideString &wsPattern, GCedLocaleIface *pLocale, WideString *pMatchFormat)
void GetNumericFormat(WideString &wsFormat, int32_t nIntLen, int32_t nDecLen)
bool ValidateNumericTemp(const WideString &wsNumeric, const WideString &wsFormat, GCedLocaleIface *pLocale)
CXFA_LocaleValue(const CXFA_LocaleValue &that)
virtual WideString GetDecimalSymbol() const =0
WideString & operator=(WideString &&that) noexcept
bool EqualsASCII(ByteStringView that) const