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