| // 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/xfa_localevalue.h" |
| |
| #include <vector> |
| |
| #include "core/fxcrt/fx_ext.h" |
| #include "third_party/base/ptr_util.h" |
| #include "third_party/base/stl_util.h" |
| #include "xfa/fgas/localization/fgas_localeimp.h" |
| #include "xfa/fxfa/parser/cxfa_document.h" |
| #include "xfa/fxfa/parser/xfa_localemgr.h" |
| #include "xfa/fxfa/parser/xfa_object.h" |
| #include "xfa/fxfa/parser/xfa_utils.h" |
| |
| static const double fraction_scales[] = {0.1, |
| 0.01, |
| 0.001, |
| 0.0001, |
| 0.00001, |
| 0.000001, |
| 0.0000001, |
| 0.00000001, |
| 0.000000001, |
| 0.0000000001, |
| 0.00000000001, |
| 0.000000000001, |
| 0.0000000000001, |
| 0.00000000000001, |
| 0.000000000000001, |
| 0.0000000000000001}; |
| CXFA_LocaleValue::CXFA_LocaleValue() { |
| m_dwType = XFA_VT_NULL; |
| m_bValid = true; |
| m_pLocaleMgr = nullptr; |
| } |
| CXFA_LocaleValue::CXFA_LocaleValue(const CXFA_LocaleValue& value) { |
| m_dwType = XFA_VT_NULL; |
| m_bValid = true; |
| m_pLocaleMgr = nullptr; |
| *this = value; |
| } |
| CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType, |
| CXFA_LocaleMgr* pLocaleMgr) { |
| m_dwType = dwType; |
| m_bValid = (m_dwType != XFA_VT_NULL); |
| m_pLocaleMgr = pLocaleMgr; |
| } |
| CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType, |
| const CFX_WideString& wsValue, |
| CXFA_LocaleMgr* pLocaleMgr) { |
| m_wsValue = wsValue; |
| m_dwType = dwType; |
| m_pLocaleMgr = pLocaleMgr; |
| m_bValid = ValidateCanonicalValue(wsValue, dwType); |
| } |
| CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType, |
| const CFX_WideString& wsValue, |
| const CFX_WideString& wsFormat, |
| IFX_Locale* pLocale, |
| CXFA_LocaleMgr* pLocaleMgr) { |
| m_pLocaleMgr = pLocaleMgr; |
| m_bValid = true; |
| 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() {} |
| static FX_LOCALECATEGORY XFA_ValugeCategory(FX_LOCALECATEGORY eCategory, |
| uint32_t dwValueType) { |
| if (eCategory == FX_LOCALECATEGORY_Unknown) { |
| 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 eCategory; |
| } |
| |
| bool CXFA_LocaleValue::ValidateValue(const CFX_WideString& wsValue, |
| const CFX_WideString& wsPattern, |
| IFX_Locale* pLocale, |
| CFX_WideString* pMatchFormat) { |
| CFX_WideString wsOutput; |
| IFX_Locale* locale = m_pLocaleMgr->GetDefLocale(); |
| if (pLocale) |
| m_pLocaleMgr->SetDefLocale(pLocale); |
| |
| auto pFormat = pdfium::MakeUnique<CFX_FormatString>(m_pLocaleMgr, false); |
| std::vector<CFX_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++) { |
| CFX_WideString wsFormat = wsPatterns[i]; |
| FX_LOCALECATEGORY eCategory = pFormat->GetCategory(wsFormat); |
| eCategory = XFA_ValugeCategory(eCategory, m_dwType); |
| switch (eCategory) { |
| 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: { |
| CFX_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_Unitime dt; |
| bRet = ValidateCanonicalDate(wsValue, dt); |
| if (!bRet) { |
| bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date, |
| dt); |
| if (!bRet) { |
| bRet = pFormat->FormatDateTime(wsValue, wsFormat, wsOutput, |
| FX_DATETIMETYPE_Date); |
| } |
| } |
| break; |
| } |
| case FX_LOCALECATEGORY_Time: { |
| CFX_Unitime dt; |
| bRet = |
| pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time, dt); |
| if (!bRet) { |
| bRet = pFormat->FormatDateTime(wsValue, wsFormat, wsOutput, |
| FX_DATETIMETYPE_Time); |
| } |
| break; |
| } |
| case FX_LOCALECATEGORY_DateTime: { |
| CFX_Unitime dt; |
| bRet = pFormat->ParseDateTime(wsValue, wsFormat, |
| FX_DATETIMETYPE_DateTime, dt); |
| if (!bRet) { |
| bRet = pFormat->FormatDateTime(wsValue, wsFormat, wsOutput, |
| FX_DATETIMETYPE_DateTime); |
| } |
| break; |
| } |
| default: |
| bRet = false; |
| break; |
| } |
| } |
| if (bRet && pMatchFormat) |
| *pMatchFormat = wsPatterns[i - 1]; |
| |
| if (pLocale) |
| m_pLocaleMgr->SetDefLocale(locale); |
| |
| return bRet; |
| } |
| |
| CFX_WideString CXFA_LocaleValue::GetValue() const { |
| return m_wsValue; |
| } |
| uint32_t CXFA_LocaleValue::GetType() const { |
| return m_dwType; |
| } |
| void CXFA_LocaleValue::SetValue(const CFX_WideString& wsValue, |
| uint32_t dwType) { |
| m_wsValue = wsValue; |
| m_dwType = dwType; |
| } |
| CFX_WideString CXFA_LocaleValue::GetText() const { |
| if (m_bValid && m_dwType == XFA_VT_TEXT) { |
| return m_wsValue; |
| } |
| return CFX_WideString(); |
| } |
| float CXFA_LocaleValue::GetNum() 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; |
| int cc = 0; |
| bool bNegative = false, 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++; |
| } |
| int 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; |
| int scale = 0; |
| double fraction = 0.0; |
| if (cc < len && str[cc] == '.') { |
| cc++; |
| while (cc < len) { |
| fraction += fraction_scales[scale] * (str[cc] - '0'); |
| scale++; |
| cc++; |
| if (scale == sizeof fraction_scales / sizeof(double) || |
| !FXSYS_isDecimalDigit(str[cc])) { |
| break; |
| } |
| } |
| dwFractional = (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; |
| } |
| float fValue = (float)(dwFractional / 4294967296.0); |
| fValue = nIntegral + (nIntegral >= 0 ? fValue : -fValue); |
| if (nExponent != 0) { |
| fValue *= FXSYS_pow(10, (float)nExponent); |
| } |
| return fValue; |
| } |
| return 0; |
| } |
| 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, 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 += fraction_scales[scale] * (str[cc] - '0'); |
| scale++; |
| cc++; |
| if (scale == sizeof fraction_scales / sizeof(double) || |
| !FXSYS_isDecimalDigit(str[cc])) { |
| break; |
| } |
| } |
| dwFractional = (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, (float)nExponent); |
| } |
| return dValue; |
| } |
| return 0; |
| } |
| CFX_Unitime CXFA_LocaleValue::GetDate() const { |
| if (m_bValid && m_dwType == XFA_VT_DATE) { |
| CFX_Unitime dt; |
| FX_DateFromCanonical(m_wsValue, dt); |
| return dt; |
| } |
| return CFX_Unitime(); |
| } |
| CFX_Unitime CXFA_LocaleValue::GetTime() const { |
| if (m_bValid && m_dwType == XFA_VT_TIME) { |
| CFX_Unitime dt(0); |
| ASSERT(m_pLocaleMgr); |
| FX_TimeFromCanonical(m_wsValue.AsStringC(), dt, |
| m_pLocaleMgr->GetDefLocale()); |
| return dt; |
| } |
| return CFX_Unitime(); |
| } |
| CFX_Unitime CXFA_LocaleValue::GetDateTime() const { |
| if (m_bValid && m_dwType == XFA_VT_DATETIME) { |
| int32_t index = m_wsValue.Find('T'); |
| CFX_Unitime dt; |
| FX_DateFromCanonical(m_wsValue.Left(index), dt); |
| ASSERT(m_pLocaleMgr); |
| FX_TimeFromCanonical( |
| m_wsValue.Right(m_wsValue.GetLength() - index - 1).AsStringC(), dt, |
| m_pLocaleMgr->GetDefLocale()); |
| return dt; |
| } |
| return CFX_Unitime(); |
| } |
| bool CXFA_LocaleValue::SetText(const CFX_WideString& wsText) { |
| m_dwType = XFA_VT_TEXT; |
| m_wsValue = wsText; |
| return true; |
| } |
| bool CXFA_LocaleValue::SetText(const CFX_WideString& wsText, |
| const CFX_WideString& wsFormat, |
| IFX_Locale* pLocale) { |
| m_dwType = XFA_VT_TEXT; |
| return m_bValid = ParsePatternValue(wsText, wsFormat, pLocale); |
| } |
| bool CXFA_LocaleValue::SetNum(float fNum) { |
| m_dwType = XFA_VT_FLOAT; |
| m_wsValue.Format(L"%.8g", (double)fNum); |
| return true; |
| } |
| bool CXFA_LocaleValue::SetNum(const CFX_WideString& wsNum, |
| const CFX_WideString& wsFormat, |
| IFX_Locale* pLocale) { |
| m_dwType = XFA_VT_FLOAT; |
| return m_bValid = ParsePatternValue(wsNum, wsFormat, pLocale); |
| } |
| bool CXFA_LocaleValue::SetDate(const CFX_Unitime& d) { |
| m_dwType = XFA_VT_DATE; |
| m_wsValue.Format(L"%04d-%02d-%02d", d.GetYear(), d.GetMonth(), d.GetDay()); |
| return true; |
| } |
| bool CXFA_LocaleValue::SetDate(const CFX_WideString& wsDate, |
| const CFX_WideString& wsFormat, |
| IFX_Locale* pLocale) { |
| m_dwType = XFA_VT_DATE; |
| return m_bValid = ParsePatternValue(wsDate, wsFormat, pLocale); |
| } |
| bool CXFA_LocaleValue::SetTime(const CFX_Unitime& t) { |
| m_dwType = XFA_VT_TIME; |
| m_wsValue.Format(L"%02d:%02d:%02d", t.GetHour(), t.GetMinute(), |
| t.GetSecond()); |
| if (t.GetMillisecond() > 0) { |
| CFX_WideString wsTemp; |
| wsTemp.Format(L"%:03d", t.GetMillisecond()); |
| m_wsValue += wsTemp; |
| } |
| return true; |
| } |
| bool CXFA_LocaleValue::SetTime(const CFX_WideString& wsTime, |
| const CFX_WideString& wsFormat, |
| IFX_Locale* pLocale) { |
| m_dwType = XFA_VT_TIME; |
| return m_bValid = ParsePatternValue(wsTime, wsFormat, pLocale); |
| } |
| bool CXFA_LocaleValue::SetDateTime(const CFX_Unitime& dt) { |
| m_dwType = XFA_VT_DATETIME; |
| m_wsValue.Format(L"%04d-%02d-%02dT%02d:%02d:%02d", dt.GetYear(), |
| dt.GetMonth(), dt.GetDay(), dt.GetHour(), dt.GetMinute(), |
| dt.GetSecond()); |
| if (dt.GetMillisecond() > 0) { |
| CFX_WideString wsTemp; |
| wsTemp.Format(L"%:03d", dt.GetMillisecond()); |
| m_wsValue += wsTemp; |
| } |
| return true; |
| } |
| bool CXFA_LocaleValue::SetDateTime(const CFX_WideString& wsDateTime, |
| const CFX_WideString& wsFormat, |
| IFX_Locale* pLocale) { |
| m_dwType = XFA_VT_DATETIME; |
| return m_bValid = ParsePatternValue(wsDateTime, wsFormat, pLocale); |
| } |
| |
| bool CXFA_LocaleValue::FormatPatterns(CFX_WideString& wsResult, |
| const CFX_WideString& wsFormat, |
| IFX_Locale* pLocale, |
| XFA_VALUEPICTURE eValueType) const { |
| auto pFormat = pdfium::MakeUnique<CFX_FormatString>(m_pLocaleMgr, false); |
| std::vector<CFX_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(CFX_WideString& wsResult, |
| const CFX_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<CFX_FormatString>(m_pLocaleMgr, false); |
| FX_LOCALECATEGORY eCategory = pFormat->GetCategory(wsFormat); |
| eCategory = XFA_ValugeCategory(eCategory, 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, wsResult, |
| FX_DATETIMETYPE_Date); |
| break; |
| case FX_LOCALECATEGORY_Time: |
| bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, wsResult, |
| FX_DATETIMETYPE_Time); |
| break; |
| case FX_LOCALECATEGORY_DateTime: |
| bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, wsResult, |
| FX_DATETIMETYPE_DateTime); |
| 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; |
| } |
| |
| static bool XFA_ValueSplitDateTime(const CFX_WideString& wsDateTime, |
| CFX_WideString& wsDate, |
| CFX_WideString& wsTime) { |
| wsDate = L""; |
| wsTime = L""; |
| if (wsDateTime.IsEmpty()) { |
| return false; |
| } |
| int nSplitIndex = -1; |
| nSplitIndex = wsDateTime.Find('T'); |
| if (nSplitIndex < 0) { |
| nSplitIndex = wsDateTime.Find(' '); |
| } |
| if (nSplitIndex < 0) { |
| return false; |
| } |
| wsDate = wsDateTime.Left(nSplitIndex); |
| wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex - 1); |
| return true; |
| } |
| bool CXFA_LocaleValue::ValidateCanonicalValue(const CFX_WideString& wsValue, |
| uint32_t dwVType) { |
| if (wsValue.IsEmpty()) { |
| return true; |
| } |
| CFX_Unitime dt; |
| switch (dwVType) { |
| case XFA_VT_DATE: { |
| if (ValidateCanonicalDate(wsValue, dt)) { |
| return true; |
| } |
| CFX_WideString wsDate, wsTime; |
| if (XFA_ValueSplitDateTime(wsValue, wsDate, wsTime) && |
| ValidateCanonicalDate(wsDate, dt)) { |
| return true; |
| } |
| return false; |
| } |
| case XFA_VT_TIME: { |
| if (ValidateCanonicalTime(wsValue)) { |
| return true; |
| } |
| CFX_WideString wsDate, wsTime; |
| if (XFA_ValueSplitDateTime(wsValue, wsDate, wsTime) && |
| ValidateCanonicalTime(wsTime)) { |
| return true; |
| } |
| return false; |
| } |
| case XFA_VT_DATETIME: { |
| CFX_WideString wsDate, wsTime; |
| if (XFA_ValueSplitDateTime(wsValue, wsDate, wsTime) && |
| ValidateCanonicalDate(wsDate, dt) && ValidateCanonicalTime(wsTime)) { |
| return true; |
| } |
| } break; |
| } |
| return true; |
| } |
| bool CXFA_LocaleValue::ValidateCanonicalDate(const CFX_WideString& wsDate, |
| CFX_Unitime& unDate) { |
| const uint16_t LastDay[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
| const uint16_t wCountY = 4, wCountM = 2, wCountD = 2; |
| int nLen = wsDate.GetLength(); |
| if (nLen < wCountY || nLen > wCountY + wCountM + wCountD + 2) { |
| return false; |
| } |
| const bool bSymbol = wsDate.Find(0x2D) != -1; |
| uint16_t wYear = 0; |
| uint16_t wMonth = 0; |
| uint16_t wDay = 0; |
| const wchar_t* pDate = wsDate.c_str(); |
| int nIndex = 0, 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) { |
| if (wMonth == 0 && nLen == wCountY) { |
| return true; |
| } |
| return false; |
| } |
| if (wDay < 1) { |
| if (wDay == 0 && (nLen == wCountY + wCountM)) { |
| return true; |
| } |
| return false; |
| } |
| 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; |
| } |
| CFX_Unitime ut; |
| ut.Set(wYear, static_cast<uint8_t>(wMonth), static_cast<uint8_t>(wDay)); |
| unDate = unDate + ut; |
| return true; |
| } |
| bool CXFA_LocaleValue::ValidateCanonicalTime(const CFX_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.Find(':') != -1; |
| 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++; |
| } |
| if (wsTime.Find('.') > 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::ValidateCanonicalDateTime( |
| const CFX_WideString& wsDateTime) { |
| CFX_WideString wsDate, wsTime; |
| if (wsDateTime.IsEmpty()) { |
| return false; |
| } |
| int nSplitIndex = -1; |
| nSplitIndex = wsDateTime.Find('T'); |
| if (nSplitIndex < 0) { |
| nSplitIndex = wsDateTime.Find(' '); |
| } |
| if (nSplitIndex < 0) { |
| return false; |
| } |
| wsDate = wsDateTime.Left(nSplitIndex); |
| wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex - 1); |
| CFX_Unitime dt; |
| return ValidateCanonicalDate(wsDate, dt) && ValidateCanonicalTime(wsTime); |
| } |
| bool CXFA_LocaleValue::ParsePatternValue(const CFX_WideString& wsValue, |
| const CFX_WideString& wsPattern, |
| IFX_Locale* pLocale) { |
| IFX_Locale* locale = m_pLocaleMgr->GetDefLocale(); |
| if (pLocale) |
| m_pLocaleMgr->SetDefLocale(pLocale); |
| |
| auto pFormat = pdfium::MakeUnique<CFX_FormatString>(m_pLocaleMgr, false); |
| std::vector<CFX_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++) { |
| CFX_WideString wsFormat = wsPatterns[i]; |
| FX_LOCALECATEGORY eCategory = pFormat->GetCategory(wsFormat); |
| eCategory = XFA_ValugeCategory(eCategory, m_dwType); |
| switch (eCategory) { |
| 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: { |
| CFX_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_Unitime 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_Unitime dt; |
| bRet = |
| pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time, dt); |
| if (bRet) { |
| SetTime(dt); |
| } |
| break; |
| } |
| case FX_LOCALECATEGORY_DateTime: { |
| CFX_Unitime 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::GetNumbericFormat(CFX_WideString& wsFormat, |
| int32_t nIntLen, |
| int32_t nDecLen, |
| bool bSign) { |
| ASSERT(wsFormat.IsEmpty()); |
| ASSERT(nIntLen >= -1 && nDecLen >= -1); |
| int32_t nTotalLen = (nIntLen >= 0 ? nIntLen : 2) + (bSign ? 1 : 0) + |
| (nDecLen >= 0 ? nDecLen : 2) + (nDecLen == 0 ? 0 : 1); |
| wchar_t* lpBuf = wsFormat.GetBuffer(nTotalLen); |
| int32_t nPos = 0; |
| if (bSign) { |
| 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(CFX_WideString& wsNumeric, |
| CFX_WideString& wsFormat, |
| IFX_Locale* pLocale, |
| int32_t* pos) { |
| 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, 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; |
| } |
| CFX_WideString wsDecimalSymbol; |
| if (pLocale) { |
| pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal, wsDecimalSymbol); |
| } else { |
| wsDecimalSymbol = CFX_WideString(L'.'); |
| } |
| if (pFmt[nf] != L'.') { |
| return false; |
| } |
| if (wsDecimalSymbol != CFX_WideStringC(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; |
| } |