summaryrefslogtreecommitdiff
path: root/svl
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2021-09-29 23:14:18 +0200
committerEike Rathke <erack@redhat.com>2021-09-30 02:04:01 +0200
commitebc454ad4eb1f4cd4d84a7db367bb71a457c4e5c (patch)
treec516e035c0fb686b59a86ff8d1f21706c0d85bc6 /svl
parent18e49d2b998ba69d5363d25d285ee6fd188a698d (diff)
Resolves: tdf#144697 Format out-of-bounds date(+time) as #FMT error
i.e. < -32768-01-01 or > 32767-12-31 They couldn't be input or stored as proleptic Gregorian in file formats anyway. Additionally in i18npool handle the absolute year values casting conversion int32 <-> int16 where era 0 BCE year 32768 is fielded as -32768 but still is a valid year for our proleptic Gregorian, so it isn't displayed as --32768. Change-Id: Ifdd482f07e04c2a4296fd0556bbef7f1d3e15676 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122835 Reviewed-by: Eike Rathke <erack@redhat.com> Tested-by: Jenkins
Diffstat (limited to 'svl')
-rw-r--r--svl/source/numbers/zforlist.cxx20
-rw-r--r--svl/source/numbers/zformat.cxx32
2 files changed, 47 insertions, 5 deletions
diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx
index 755dda187b9b..185dc97f12fa 100644
--- a/svl/source/numbers/zforlist.cxx
+++ b/svl/source/numbers/zforlist.cxx
@@ -1713,6 +1713,7 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
{
pFormat = GetFormatEntry( nKey );
}
+ assert(pFormat);
if (pFormat)
{
if ( eType == SvNumFormatType::TIME && pFormat->GetFormatPrecision() )
@@ -1720,7 +1721,24 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
ChangeStandardPrec(INPUTSTRING_PRECISION);
bPrecChanged = true;
}
- pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
+ const bool bOk = pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
+
+ // The #FMT error string must not be used for input as it would lead to
+ // data loss. This can happen for at least date(+time). Fall back to a
+ // last resort of plain number in the locale the formatter was
+ // contructed with.
+ if (!bOk && eType != SvNumFormatType::NUMBER && sOutString == ImpSvNumberformatScan::sErrStr)
+ {
+ pFormat = GetFormatEntry(ZF_STANDARD);
+ assert(pFormat);
+ if (pFormat)
+ {
+ ChangeStandardPrec(INPUTSTRING_PRECISION);
+ bPrecChanged = true;
+ pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
+ }
+ }
+ assert(sOutString != ImpSvNumberformatScan::sErrStr);
}
if (bPrecChanged)
{
diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx
index 0f618e75ca02..53eb8181c2d6 100644
--- a/svl/source/numbers/zformat.cxx
+++ b/svl/source/numbers/zformat.cxx
@@ -3647,6 +3647,24 @@ static bool lcl_isSignedYear( const CalendarWrapper& rCal, const ImpSvNumFor& rN
rCal.getUniqueID() == GREGORIAN && !lcl_hasEra( rNumFor );
}
+/* XXX: if needed this could be stripped from rEpochStart and diff adding and
+ * moved to tools' DateTime to be reused elsewhere. */
+static bool lcl_getValidDate( const DateTime& rNullDate, const DateTime& rEpochStart, double& fNumber )
+{
+ static const DateTime aCE( Date(1,1,1));
+ static const DateTime aMin( Date(1,1, SAL_MIN_INT16));
+ static const DateTime aMax( Date(31,12, SAL_MAX_INT16), tools::Time(23,59,59, tools::Time::nanoSecPerSec - 1));
+ static const double fMin = aMin - aCE;
+ static const double fMax = aMax - aCE;
+ // Value must be representable in our tools::Date proleptic Gregorian
+ // calendar as well.
+ const double fOff = (rNullDate - aCE) + fNumber;
+ // Add diff between epochs to serial date number.
+ const double fDiff = rNullDate - rEpochStart;
+ fNumber += fDiff;
+ return fMin <= fOff && fOff <= fMax;
+}
+
bool SvNumberformat::ImpGetDateOutput(double fNumber,
sal_uInt16 nIx,
OUStringBuffer& sBuff)
@@ -3655,8 +3673,11 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber,
bool bRes = false;
CalendarWrapper& rCal = GetCal();
- double fDiff = DateTime(rScan.GetNullDate()) - rCal.getEpochStart();
- fNumber += fDiff;
+ if (!lcl_getValidDate( rScan.GetNullDate(), rCal.getEpochStart(), fNumber))
+ {
+ sBuff = ImpSvNumberformatScan::sErrStr;
+ return false;
+ }
rCal.setLocalDateTime( fNumber );
int nUseMonthCase = 0; // Not decided yet
OUString aOrgCalendar; // empty => not changed yet
@@ -3922,8 +3943,11 @@ bool SvNumberformat::ImpGetDateTimeOutput(double fNumber,
bool bRes = false;
CalendarWrapper& rCal = GetCal();
- double fDiff = DateTime(rScan.GetNullDate()) - rCal.getEpochStart();
- fNumber += fDiff;
+ if (!lcl_getValidDate( rScan.GetNullDate(), rCal.getEpochStart(), fNumber))
+ {
+ sBuff = ImpSvNumberformatScan::sErrStr;
+ return false;
+ }
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
bool bInputLine;