| // Copyright 2014 PDFium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| #include "xfa/fxfa/parser/cxfa_localevalue.h" | |
| #include <vector> | |
| #include "core/fxcrt/fx_extension.h" | |
| #include "third_party/base/ptr_util.h" | |
| #include "third_party/base/stl_util.h" | |
| #include "xfa/fgas/crt/cfgas_formatstring.h" | |
| #include "xfa/fxfa/parser/cxfa_document.h" | |
| #include "xfa/fxfa/parser/cxfa_localemgr.h" | |
| #include "xfa/fxfa/parser/xfa_utils.h" | |
| namespace { | |
| FX_LOCALECATEGORY ValueCategory(FX_LOCALECATEGORY eCategory, | |
| uint32_t dwValueType) { | |
| if (eCategory != FX_LOCALECATEGORY_Unknown) | |
| return eCategory; | |
| switch (dwValueType) { | |
| case XFA_VT_BOOLEAN: | |
| case XFA_VT_INTEGER: | |
| case XFA_VT_DECIMAL: | |
| case XFA_VT_FLOAT: | |
| return FX_LOCALECATEGORY_Num; | |
| case XFA_VT_TEXT: | |
| return FX_LOCALECATEGORY_Text; | |
| case XFA_VT_DATE: | |
| return FX_LOCALECATEGORY_Date; | |
| case XFA_VT_TIME: | |
| return FX_LOCALECATEGORY_Time; | |
| case XFA_VT_DATETIME: | |
| return FX_LOCALECATEGORY_DateTime; | |
| } | |
| return FX_LOCALECATEGORY_Unknown; | |
| } | |
| bool ValueSplitDateTime(const WideString& wsDateTime, | |
| WideString& wsDate, | |
| WideString& wsTime) { | |
| wsDate = L""; | |
| wsTime = L""; | |
| if (wsDateTime.IsEmpty()) | |
| return false; | |
| auto nSplitIndex = wsDateTime.Find('T'); | |
| if (!nSplitIndex.has_value()) | |
| nSplitIndex = wsDateTime.Find(' '); | |
| if (!nSplitIndex.has_value()) | |
| return false; | |
| wsDate = wsDateTime.Left(nSplitIndex.value()); | |
| wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex.value() - 1); | |
| return true; | |
| } | |
| } // namespace | |
| CXFA_LocaleValue::CXFA_LocaleValue() | |
| : m_pLocaleMgr(nullptr), m_dwType(XFA_VT_NULL), m_bValid(true) {} | |
| CXFA_LocaleValue::CXFA_LocaleValue(const CXFA_LocaleValue& value) | |
| : m_pLocaleMgr(value.m_pLocaleMgr), | |
| m_wsValue(value.m_wsValue), | |
| m_dwType(value.m_dwType), | |
| m_bValid(value.m_bValid) {} | |
| CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType, CXFA_LocaleMgr* pLocaleMgr) | |
| : m_pLocaleMgr(pLocaleMgr), | |
| m_dwType(dwType), | |
| m_bValid(m_dwType != XFA_VT_NULL) {} | |
| CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType, | |
| const WideString& wsValue, | |
| CXFA_LocaleMgr* pLocaleMgr) | |
| : m_pLocaleMgr(pLocaleMgr), | |
| m_wsValue(wsValue), | |
| m_dwType(dwType), | |
| m_bValid(ValidateCanonicalValue(wsValue, dwType)) {} | |
| CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType, | |
| const WideString& wsValue, | |
| const WideString& wsFormat, | |
| IFX_Locale* pLocale, | |
| CXFA_LocaleMgr* pLocaleMgr) | |
| : m_pLocaleMgr(pLocaleMgr), | |
| m_dwType(dwType), | |
| m_bValid(ParsePatternValue(wsValue, wsFormat, pLocale)) {} | |
| CXFA_LocaleValue& CXFA_LocaleValue::operator=(const CXFA_LocaleValue& value) { | |
| m_wsValue = value.m_wsValue; | |
| m_dwType = value.m_dwType; | |
| m_bValid = value.m_bValid; | |
| m_pLocaleMgr = value.m_pLocaleMgr; | |
| return *this; | |
| } | |
| CXFA_LocaleValue::~CXFA_LocaleValue() {} | |
| bool CXFA_LocaleValue::ValidateValue(const WideString& wsValue, | |
| const WideString& wsPattern, | |
| IFX_Locale* pLocale, | |
| WideString* pMatchFormat) { | |
| WideString wsOutput; | |
| IFX_Locale* locale = m_pLocaleMgr->GetDefLocale(); | |
| if (pLocale) | |
| m_pLocaleMgr->SetDefLocale(pLocale); | |
| auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr); | |
| std::vector<WideString> wsPatterns; | |
| pFormat->SplitFormatString(wsPattern, &wsPatterns); | |
| bool bRet = false; | |
| int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns); | |
| int32_t i = 0; | |
| for (; i < iCount && !bRet; i++) { | |
| WideString wsFormat = wsPatterns[i]; | |
| switch (ValueCategory(pFormat->GetCategory(wsFormat), m_dwType)) { | |
| case FX_LOCALECATEGORY_Null: | |
| bRet = pFormat->ParseNull(wsValue, wsFormat); | |
| if (!bRet) | |
| bRet = wsValue.IsEmpty(); | |
| break; | |
| case FX_LOCALECATEGORY_Zero: | |
| bRet = pFormat->ParseZero(wsValue, wsFormat); | |
| if (!bRet) | |
| bRet = wsValue == L"0"; | |
| break; | |
| case FX_LOCALECATEGORY_Num: { | |
| WideString fNum; | |
| bRet = pFormat->ParseNum(wsValue, wsFormat, &fNum); | |
| if (!bRet) | |
| bRet = pFormat->FormatNum(wsValue, wsFormat, &wsOutput); | |
| break; | |
| } | |
| case FX_LOCALECATEGORY_Text: | |
| bRet = pFormat->ParseText(wsValue, wsFormat, &wsOutput); | |
| wsOutput.clear(); | |
| if (!bRet) | |
| bRet = pFormat->FormatText(wsValue, wsFormat, &wsOutput); | |
| break; | |
| case FX_LOCALECATEGORY_Date: { | |
| CFX_DateTime dt; | |
| bRet = ValidateCanonicalDate(wsValue, &dt); | |
| if (!bRet) { | |
| bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date, | |
| &dt); | |
| if (!bRet) { | |
| bRet = pFormat->FormatDateTime(wsValue, wsFormat, | |
| FX_DATETIMETYPE_Date, &wsOutput); | |
| } | |
| } | |
| break; | |
| } | |
| case FX_LOCALECATEGORY_Time: { | |
| CFX_DateTime dt; | |
| bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time, | |
| &dt); | |
| if (!bRet) { | |
| bRet = pFormat->FormatDateTime(wsValue, wsFormat, | |
| FX_DATETIMETYPE_Time, &wsOutput); | |
| } | |
| break; | |
| } | |
| case FX_LOCALECATEGORY_DateTime: { | |
| CFX_DateTime dt; | |
| bRet = pFormat->ParseDateTime(wsValue, wsFormat, | |
| FX_DATETIMETYPE_DateTime, &dt); | |
| if (!bRet) { | |
| bRet = pFormat->FormatDateTime(wsValue, wsFormat, | |
| FX_DATETIMETYPE_DateTime, &wsOutput); | |
| } | |
| break; | |
| } | |
| default: | |
| bRet = false; | |
| break; | |
| } | |
| } | |
| if (bRet && pMatchFormat) | |
| *pMatchFormat = wsPatterns[i - 1]; | |
| if (pLocale) | |
| m_pLocaleMgr->SetDefLocale(locale); | |
| return bRet; | |
| } | |
| double CXFA_LocaleValue::GetDoubleNum() const { | |
| if (m_bValid && (m_dwType == XFA_VT_BOOLEAN || m_dwType == XFA_VT_INTEGER || | |
| m_dwType == XFA_VT_DECIMAL || m_dwType == XFA_VT_FLOAT)) { | |
| int64_t nIntegral = 0; | |
| uint32_t dwFractional = 0; | |
| int32_t nExponent = 0; | |
| int32_t cc = 0; | |
| bool bNegative = false; | |
| bool bExpSign = false; | |
| const wchar_t* str = m_wsValue.c_str(); | |
| int len = m_wsValue.GetLength(); | |
| while (FXSYS_iswspace(str[cc]) && cc < len) | |
| cc++; | |
| if (cc >= len) | |
| return 0; | |
| if (str[0] == '+') { | |
| cc++; | |
| } else if (str[0] == '-') { | |
| bNegative = true; | |
| cc++; | |
| } | |
| int32_t nIntegralLen = 0; | |
| while (cc < len) { | |
| if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc]) || | |
| nIntegralLen > 17) { | |
| break; | |
| } | |
| nIntegral = nIntegral * 10 + str[cc] - '0'; | |
| cc++; | |
| nIntegralLen++; | |
| } | |
| nIntegral = bNegative ? -nIntegral : nIntegral; | |
| int32_t scale = 0; | |
| double fraction = 0.0; | |
| if (cc < len && str[cc] == '.') { | |
| cc++; | |
| while (cc < len) { | |
| fraction += XFA_GetFractionalScale(scale) * (str[cc] - '0'); | |
| scale++; | |
| cc++; | |
| if (scale == XFA_GetMaxFractionalScale() || | |
| !FXSYS_isDecimalDigit(str[cc])) { | |
| break; | |
| } | |
| } | |
| dwFractional = static_cast<uint32_t>(fraction * 4294967296.0); | |
| } | |
| if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) { | |
| cc++; | |
| if (cc < len) { | |
| if (str[cc] == '+') { | |
| cc++; | |
| } else if (str[cc] == '-') { | |
| bExpSign = true; | |
| cc++; | |
| } | |
| } | |
| while (cc < len) { | |
| if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc])) | |
| break; | |
| nExponent = nExponent * 10 + str[cc] - '0'; | |
| cc++; | |
| } | |
| nExponent = bExpSign ? -nExponent : nExponent; | |
| } | |
| double dValue = dwFractional / 4294967296.0; | |
| dValue = nIntegral + (nIntegral >= 0 ? dValue : -dValue); | |
| if (nExponent != 0) | |
| dValue *= FXSYS_pow(10, static_cast<float>(nExponent)); | |
| return dValue; | |
| } | |
| return 0; | |
| } | |
| CFX_DateTime CXFA_LocaleValue::GetDate() const { | |
| if (!m_bValid || m_dwType != XFA_VT_DATE) | |
| return CFX_DateTime(); | |
| CFX_DateTime dt; | |
| FX_DateFromCanonical(m_wsValue, &dt); | |
| return dt; | |
| } | |
| CFX_DateTime CXFA_LocaleValue::GetTime() const { | |
| if (!m_bValid || m_dwType != XFA_VT_TIME) | |
| return CFX_DateTime(); | |
| CFX_DateTime dt; | |
| FX_TimeFromCanonical(m_wsValue.AsStringView(), &dt, | |
| m_pLocaleMgr->GetDefLocale()); | |
| return dt; | |
| } | |
| bool CXFA_LocaleValue::SetDate(const CFX_DateTime& d) { | |
| m_dwType = XFA_VT_DATE; | |
| m_wsValue = WideString::Format(L"%04d-%02d-%02d", d.GetYear(), d.GetMonth(), | |
| d.GetDay()); | |
| return true; | |
| } | |
| bool CXFA_LocaleValue::SetTime(const CFX_DateTime& t) { | |
| m_dwType = XFA_VT_TIME; | |
| m_wsValue = WideString::Format(L"%02d:%02d:%02d", t.GetHour(), t.GetMinute(), | |
| t.GetSecond()); | |
| if (t.GetMillisecond() > 0) | |
| m_wsValue += WideString::Format(L"%:03d", t.GetMillisecond()); | |
| return true; | |
| } | |
| bool CXFA_LocaleValue::SetDateTime(const CFX_DateTime& dt) { | |
| m_dwType = XFA_VT_DATETIME; | |
| m_wsValue = WideString::Format(L"%04d-%02d-%02dT%02d:%02d:%02d", dt.GetYear(), | |
| dt.GetMonth(), dt.GetDay(), dt.GetHour(), | |
| dt.GetMinute(), dt.GetSecond()); | |
| if (dt.GetMillisecond() > 0) | |
| m_wsValue += WideString::Format(L"%:03d", dt.GetMillisecond()); | |
| return true; | |
| } | |
| bool CXFA_LocaleValue::FormatPatterns(WideString& wsResult, | |
| const WideString& wsFormat, | |
| IFX_Locale* pLocale, | |
| XFA_VALUEPICTURE eValueType) const { | |
| auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr); | |
| std::vector<WideString> wsPatterns; | |
| pFormat->SplitFormatString(wsFormat, &wsPatterns); | |
| wsResult.clear(); | |
| int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns); | |
| for (int32_t i = 0; i < iCount; i++) { | |
| if (FormatSinglePattern(wsResult, wsPatterns[i], pLocale, eValueType)) | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool CXFA_LocaleValue::FormatSinglePattern(WideString& wsResult, | |
| const WideString& wsFormat, | |
| IFX_Locale* pLocale, | |
| XFA_VALUEPICTURE eValueType) const { | |
| IFX_Locale* locale = m_pLocaleMgr->GetDefLocale(); | |
| if (pLocale) | |
| m_pLocaleMgr->SetDefLocale(pLocale); | |
| wsResult.clear(); | |
| bool bRet = false; | |
| auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr); | |
| FX_LOCALECATEGORY eCategory = | |
| ValueCategory(pFormat->GetCategory(wsFormat), m_dwType); | |
| switch (eCategory) { | |
| case FX_LOCALECATEGORY_Null: | |
| if (m_wsValue.IsEmpty()) | |
| bRet = pFormat->FormatNull(wsFormat, &wsResult); | |
| break; | |
| case FX_LOCALECATEGORY_Zero: | |
| if (m_wsValue == L"0") | |
| bRet = pFormat->FormatZero(wsFormat, &wsResult); | |
| break; | |
| case FX_LOCALECATEGORY_Num: | |
| bRet = pFormat->FormatNum(m_wsValue, wsFormat, &wsResult); | |
| break; | |
| case FX_LOCALECATEGORY_Text: | |
| bRet = pFormat->FormatText(m_wsValue, wsFormat, &wsResult); | |
| break; | |
| case FX_LOCALECATEGORY_Date: | |
| bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, FX_DATETIMETYPE_Date, | |
| &wsResult); | |
| break; | |
| case FX_LOCALECATEGORY_Time: | |
| bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, FX_DATETIMETYPE_Time, | |
| &wsResult); | |
| break; | |
| case FX_LOCALECATEGORY_DateTime: | |
| bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, | |
| FX_DATETIMETYPE_DateTime, &wsResult); | |
| break; | |
| default: | |
| wsResult = m_wsValue; | |
| bRet = true; | |
| } | |
| if (!bRet && (eCategory != FX_LOCALECATEGORY_Num || | |
| eValueType != XFA_VALUEPICTURE_Display)) { | |
| wsResult = m_wsValue; | |
| } | |
| if (pLocale) | |
| m_pLocaleMgr->SetDefLocale(locale); | |
| return bRet; | |
| } | |
| bool CXFA_LocaleValue::ValidateCanonicalValue(const WideString& wsValue, | |
| uint32_t dwVType) { | |
| if (wsValue.IsEmpty()) | |
| return true; | |
| CFX_DateTime dt; | |
| switch (dwVType) { | |
| case XFA_VT_DATE: { | |
| if (ValidateCanonicalDate(wsValue, &dt)) | |
| return true; | |
| WideString wsDate; | |
| WideString wsTime; | |
| if (ValueSplitDateTime(wsValue, wsDate, wsTime) && | |
| ValidateCanonicalDate(wsDate, &dt)) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| case XFA_VT_TIME: { | |
| if (ValidateCanonicalTime(wsValue)) | |
| return true; | |
| WideString wsDate; | |
| WideString wsTime; | |
| if (ValueSplitDateTime(wsValue, wsDate, wsTime) && | |
| ValidateCanonicalTime(wsTime)) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| case XFA_VT_DATETIME: { | |
| WideString wsDate, wsTime; | |
| if (ValueSplitDateTime(wsValue, wsDate, wsTime) && | |
| ValidateCanonicalDate(wsDate, &dt) && ValidateCanonicalTime(wsTime)) { | |
| return true; | |
| } | |
| } break; | |
| } | |
| return true; | |
| } | |
| bool CXFA_LocaleValue::ValidateCanonicalDate(const WideString& wsDate, | |
| CFX_DateTime* unDate) { | |
| static const uint16_t LastDay[12] = {31, 28, 31, 30, 31, 30, | |
| 31, 31, 30, 31, 30, 31}; | |
| static const uint16_t wCountY = 4; | |
| static const uint16_t wCountM = 2; | |
| static const uint16_t wCountD = 2; | |
| int nLen = wsDate.GetLength(); | |
| if (nLen < wCountY || nLen > wCountY + wCountM + wCountD + 2) | |
| return false; | |
| const bool bSymbol = wsDate.Contains(0x2D); | |
| uint16_t wYear = 0; | |
| uint16_t wMonth = 0; | |
| uint16_t wDay = 0; | |
| const wchar_t* pDate = wsDate.c_str(); | |
| int nIndex = 0; | |
| int nStart = 0; | |
| while (pDate[nIndex] != '\0' && nIndex < wCountY) { | |
| if (!FXSYS_isDecimalDigit(pDate[nIndex])) | |
| return false; | |
| wYear = (pDate[nIndex] - '0') + wYear * 10; | |
| nIndex++; | |
| } | |
| if (bSymbol) { | |
| if (pDate[nIndex] != 0x2D) | |
| return false; | |
| nIndex++; | |
| } | |
| nStart = nIndex; | |
| while (pDate[nIndex] != '\0' && nIndex - nStart < wCountM && nIndex < nLen) { | |
| if (!FXSYS_isDecimalDigit(pDate[nIndex])) | |
| return false; | |
| wMonth = (pDate[nIndex] - '0') + wMonth * 10; | |
| nIndex++; | |
| } | |
| if (bSymbol) { | |
| if (pDate[nIndex] != 0x2D) | |
| return false; | |
| nIndex++; | |
| } | |
| nStart = nIndex; | |
| while (pDate[nIndex] != '\0' && nIndex - nStart < wCountD && nIndex < nLen) { | |
| if (!FXSYS_isDecimalDigit(pDate[nIndex])) | |
| return false; | |
| wDay = (pDate[nIndex] - '0') + wDay * 10; | |
| nIndex++; | |
| } | |
| if (nIndex != nLen) | |
| return false; | |
| if (wYear < 1900 || wYear > 2029) | |
| return false; | |
| if (wMonth < 1 || wMonth > 12) | |
| return wMonth == 0 && nLen == wCountY; | |
| if (wDay < 1) | |
| return wDay == 0 && (nLen == wCountY + wCountM); | |
| if (wMonth == 2) { | |
| if (wYear % 400 == 0 || (wYear % 100 != 0 && wYear % 4 == 0)) { | |
| if (wDay > 29) | |
| return false; | |
| } else if (wDay > 28) { | |
| return false; | |
| } | |
| } else if (wDay > LastDay[wMonth - 1]) { | |
| return false; | |
| } | |
| unDate->SetDate(wYear, static_cast<uint8_t>(wMonth), | |
| static_cast<uint8_t>(wDay)); | |
| return true; | |
| } | |
| bool CXFA_LocaleValue::ValidateCanonicalTime(const WideString& wsTime) { | |
| int nLen = wsTime.GetLength(); | |
| if (nLen < 2) | |
| return false; | |
| const uint16_t wCountH = 2; | |
| const uint16_t wCountM = 2; | |
| const uint16_t wCountS = 2; | |
| const uint16_t wCountF = 3; | |
| const bool bSymbol = wsTime.Contains(':'); | |
| uint16_t wHour = 0; | |
| uint16_t wMinute = 0; | |
| uint16_t wSecond = 0; | |
| uint16_t wFraction = 0; | |
| const wchar_t* pTime = wsTime.c_str(); | |
| int nIndex = 0; | |
| int nStart = 0; | |
| while (nIndex - nStart < wCountH && pTime[nIndex]) { | |
| if (!FXSYS_isDecimalDigit(pTime[nIndex])) | |
| return false; | |
| wHour = pTime[nIndex] - '0' + wHour * 10; | |
| nIndex++; | |
| } | |
| if (bSymbol) { | |
| if (nIndex < nLen && pTime[nIndex] != ':') | |
| return false; | |
| nIndex++; | |
| } | |
| nStart = nIndex; | |
| while (nIndex - nStart < wCountM && nIndex < nLen && pTime[nIndex]) { | |
| if (!FXSYS_isDecimalDigit(pTime[nIndex])) | |
| return false; | |
| wMinute = pTime[nIndex] - '0' + wMinute * 10; | |
| nIndex++; | |
| } | |
| if (bSymbol) { | |
| if (nIndex < nLen && pTime[nIndex] != ':') | |
| return false; | |
| nIndex++; | |
| } | |
| nStart = nIndex; | |
| while (nIndex - nStart < wCountS && nIndex < nLen && pTime[nIndex]) { | |
| if (!FXSYS_isDecimalDigit(pTime[nIndex])) | |
| return false; | |
| wSecond = pTime[nIndex] - '0' + wSecond * 10; | |
| nIndex++; | |
| } | |
| auto pos = wsTime.Find('.'); | |
| if (pos.has_value() && pos.value() != 0) { | |
| if (pTime[nIndex] != '.') | |
| return false; | |
| nIndex++; | |
| nStart = nIndex; | |
| while (nIndex - nStart < wCountF && nIndex < nLen && pTime[nIndex]) { | |
| if (!FXSYS_isDecimalDigit(pTime[nIndex])) | |
| return false; | |
| wFraction = pTime[nIndex] - '0' + wFraction * 10; | |
| nIndex++; | |
| } | |
| } | |
| if (nIndex < nLen) { | |
| if (pTime[nIndex] == 'Z') { | |
| nIndex++; | |
| } else if (pTime[nIndex] == '-' || pTime[nIndex] == '+') { | |
| int16_t nOffsetH = 0; | |
| int16_t nOffsetM = 0; | |
| nIndex++; | |
| nStart = nIndex; | |
| while (nIndex - nStart < wCountH && nIndex < nLen && pTime[nIndex]) { | |
| if (!FXSYS_isDecimalDigit(pTime[nIndex])) | |
| return false; | |
| nOffsetH = pTime[nIndex] - '0' + nOffsetH * 10; | |
| nIndex++; | |
| } | |
| if (bSymbol) { | |
| if (nIndex < nLen && pTime[nIndex] != ':') | |
| return false; | |
| nIndex++; | |
| } | |
| nStart = nIndex; | |
| while (nIndex - nStart < wCountM && nIndex < nLen && pTime[nIndex]) { | |
| if (!FXSYS_isDecimalDigit(pTime[nIndex])) | |
| return false; | |
| nOffsetM = pTime[nIndex] - '0' + nOffsetM * 10; | |
| nIndex++; | |
| } | |
| if (nOffsetH > 12 || nOffsetM >= 60) | |
| return false; | |
| } | |
| } | |
| return nIndex == nLen && wHour < 24 && wMinute < 60 && wSecond < 60 && | |
| wFraction <= 999; | |
| } | |
| bool CXFA_LocaleValue::ParsePatternValue(const WideString& wsValue, | |
| const WideString& wsPattern, | |
| IFX_Locale* pLocale) { | |
| IFX_Locale* locale = m_pLocaleMgr->GetDefLocale(); | |
| if (pLocale) | |
| m_pLocaleMgr->SetDefLocale(pLocale); | |
| auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr); | |
| std::vector<WideString> wsPatterns; | |
| pFormat->SplitFormatString(wsPattern, &wsPatterns); | |
| bool bRet = false; | |
| int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns); | |
| for (int32_t i = 0; i < iCount && !bRet; i++) { | |
| WideString wsFormat = wsPatterns[i]; | |
| switch (ValueCategory(pFormat->GetCategory(wsFormat), m_dwType)) { | |
| case FX_LOCALECATEGORY_Null: | |
| bRet = pFormat->ParseNull(wsValue, wsFormat); | |
| if (bRet) | |
| m_wsValue.clear(); | |
| break; | |
| case FX_LOCALECATEGORY_Zero: | |
| bRet = pFormat->ParseZero(wsValue, wsFormat); | |
| if (bRet) | |
| m_wsValue = L"0"; | |
| break; | |
| case FX_LOCALECATEGORY_Num: { | |
| WideString fNum; | |
| bRet = pFormat->ParseNum(wsValue, wsFormat, &fNum); | |
| if (bRet) | |
| m_wsValue = fNum; | |
| break; | |
| } | |
| case FX_LOCALECATEGORY_Text: | |
| bRet = pFormat->ParseText(wsValue, wsFormat, &m_wsValue); | |
| break; | |
| case FX_LOCALECATEGORY_Date: { | |
| CFX_DateTime dt; | |
| bRet = ValidateCanonicalDate(wsValue, &dt); | |
| if (!bRet) { | |
| bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date, | |
| &dt); | |
| } | |
| if (bRet) | |
| SetDate(dt); | |
| break; | |
| } | |
| case FX_LOCALECATEGORY_Time: { | |
| CFX_DateTime dt; | |
| bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time, | |
| &dt); | |
| if (bRet) | |
| SetTime(dt); | |
| break; | |
| } | |
| case FX_LOCALECATEGORY_DateTime: { | |
| CFX_DateTime dt; | |
| bRet = pFormat->ParseDateTime(wsValue, wsFormat, | |
| FX_DATETIMETYPE_DateTime, &dt); | |
| if (bRet) | |
| SetDateTime(dt); | |
| break; | |
| } | |
| default: | |
| m_wsValue = wsValue; | |
| bRet = true; | |
| break; | |
| } | |
| } | |
| if (!bRet) | |
| m_wsValue = wsValue; | |
| if (pLocale) | |
| m_pLocaleMgr->SetDefLocale(locale); | |
| return bRet; | |
| } | |
| void CXFA_LocaleValue::GetNumericFormat(WideString& wsFormat, | |
| int32_t nIntLen, | |
| int32_t nDecLen) { | |
| ASSERT(wsFormat.IsEmpty()); | |
| ASSERT(nIntLen >= -1 && nDecLen >= -1); | |
| int32_t nTotalLen = (nIntLen >= 0 ? nIntLen : 2) + 1 + | |
| (nDecLen >= 0 ? nDecLen : 2) + (nDecLen == 0 ? 0 : 1); | |
| wchar_t* lpBuf = wsFormat.GetBuffer(nTotalLen); | |
| int32_t nPos = 0; | |
| lpBuf[nPos++] = L's'; | |
| if (nIntLen == -1) { | |
| lpBuf[nPos++] = L'z'; | |
| lpBuf[nPos++] = L'*'; | |
| } else { | |
| while (nIntLen) { | |
| lpBuf[nPos++] = L'z'; | |
| nIntLen--; | |
| } | |
| } | |
| if (nDecLen != 0) { | |
| lpBuf[nPos++] = L'.'; | |
| } | |
| if (nDecLen == -1) { | |
| lpBuf[nPos++] = L'z'; | |
| lpBuf[nPos++] = L'*'; | |
| } else { | |
| while (nDecLen) { | |
| lpBuf[nPos++] = L'z'; | |
| nDecLen--; | |
| } | |
| } | |
| wsFormat.ReleaseBuffer(nTotalLen); | |
| } | |
| bool CXFA_LocaleValue::ValidateNumericTemp(const WideString& wsNumeric, | |
| const WideString& wsFormat, | |
| IFX_Locale* pLocale) { | |
| if (wsFormat.IsEmpty() || wsNumeric.IsEmpty()) | |
| return true; | |
| const wchar_t* pNum = wsNumeric.c_str(); | |
| const wchar_t* pFmt = wsFormat.c_str(); | |
| int32_t n = 0; | |
| int32_t nf = 0; | |
| wchar_t c = pNum[n]; | |
| wchar_t cf = pFmt[nf]; | |
| if (cf == L's') { | |
| if (c == L'-' || c == L'+') | |
| ++n; | |
| ++nf; | |
| } | |
| bool bLimit = true; | |
| int32_t nCount = wsNumeric.GetLength(); | |
| int32_t nCountFmt = wsFormat.GetLength(); | |
| while (n < nCount && (bLimit ? nf < nCountFmt : true) && | |
| FXSYS_isDecimalDigit(c = pNum[n])) { | |
| if (bLimit == true) { | |
| if ((cf = pFmt[nf]) == L'*') | |
| bLimit = false; | |
| else if (cf == L'z') | |
| nf++; | |
| else | |
| return false; | |
| } | |
| n++; | |
| } | |
| if (n == nCount) | |
| return true; | |
| if (nf == nCountFmt) | |
| return false; | |
| while (nf < nCountFmt && (cf = pFmt[nf]) != L'.') { | |
| ASSERT(cf == L'z' || cf == L'*'); | |
| ++nf; | |
| } | |
| WideString wsDecimalSymbol; | |
| if (pLocale) | |
| wsDecimalSymbol = pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal); | |
| else | |
| wsDecimalSymbol = WideString(L'.'); | |
| if (pFmt[nf] != L'.') | |
| return false; | |
| if (wsDecimalSymbol != WideStringView(c) && c != L'.') | |
| return false; | |
| ++nf; | |
| ++n; | |
| bLimit = true; | |
| while (n < nCount && (bLimit ? nf < nCountFmt : true) && | |
| FXSYS_isDecimalDigit(c = pNum[n])) { | |
| if (bLimit == true) { | |
| if ((cf = pFmt[nf]) == L'*') | |
| bLimit = false; | |
| else if (cf == L'z') | |
| nf++; | |
| else | |
| return false; | |
| } | |
| n++; | |
| } | |
| return n == nCount; | |
| } |