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