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