mso-test: invalid datetime in props

This is using the test document from tdf119234-3.odt.
When importing and exporting to DOCX, we generate an invalid entry in
  docprops/custom.xml
because we dont know how to handle a DateTimeWithTimezone value..

Change-Id: I79981f8a09db432730a9b0c1cf186305b0055923
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193400
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Michael Stahl <michael.stahl@collabora.com>
(cherry picked from commit 97cf170c20c7ff1e1b3820a769cd3167a57d0c46)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193600
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Tested-by: Jenkins
This commit is contained in:
Noel Grandin
2025-11-08 13:11:38 +01:00
parent 1c8b8d1fb8
commit 5a9e966b32
3 changed files with 77 additions and 18 deletions
+6
View File
@@ -259,6 +259,12 @@ public:
sal_Int16 const* pTimeZoneOffset,
bool bAddTimeIf0AM = false );
/** convert util::DateTime to XMLSchema-2 "date" or "dateTime" string */
static void convertDateTime( OStringBuffer& rBuffer,
const css::util::DateTime& rDateTime,
sal_Int16 const* pTimeZoneOffset,
bool bAddTimeIf0AM = false );
/** convert util::DateTime to XMLSchema-2 "time" or "dateTime" string */
static void convertTimeOrDateTime(OUStringBuffer& rBuffer,
const css::util::DateTime& rDateTime);
+29
View File
@@ -28,6 +28,7 @@
#include <com/sun/star/embed/XRelationshipAccess.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/text/XTextDocument.hpp>
#include <com/sun/star/util/DateTimeWithTimezone.hpp>
#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
#include <com/sun/star/xml/sax/XSAXSerializable.hpp>
#include <com/sun/star/xml/sax/Writer.hpp>
@@ -624,6 +625,31 @@ writeElement( const FSHelperPtr& pDoc, sal_Int32 nXmlElement, const util::DateTi
pDoc->endElement( nXmlElement );
}
static void
writeElement( const FSHelperPtr& pDoc, sal_Int32 nXmlElement, const util::DateTimeWithTimezone& rTime )
{
if (rTime.Timezone == 0)
{
writeElement(pDoc, nXmlElement, rTime.DateTimeInTZ);
return;
}
if( rTime.DateTimeInTZ.Year == 0 )
return;
if ( ( nXmlElement >> 16 ) != XML_dcterms )
pDoc->startElement(nXmlElement);
else
pDoc->startElement(nXmlElement, FSNS(XML_xsi, XML_type), "dcterms:W3CDTF");
OStringBuffer aStr;
sax::Converter::convertDateTime(aStr, rTime.DateTimeInTZ, &rTime.Timezone);
pDoc->write( aStr );
pDoc->endElement( nXmlElement );
}
static void
writeElement( const FSHelperPtr& pDoc, sal_Int32 nXmlElement, const Sequence< OUString >& aItems )
{
@@ -976,6 +1002,7 @@ writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentPropertie
util::Date aDate;
util::Duration aDuration;
util::DateTime aDateTime;
util::DateTimeWithTimezone aDateTimeTZ;
if ( rProp.Value >>= num )
{
// i4 - 4-byte signed integer
@@ -995,6 +1022,8 @@ writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentPropertie
}
else if ( rProp.Value >>= aDateTime )
writeElement( pAppProps, FSNS( XML_vt, XML_filetime ), aDateTime );
else if ( rProp.Value >>= aDateTimeTZ )
writeElement( pAppProps, FSNS( XML_vt, XML_filetime ), aDateTimeTZ );
else
//no other options
OSL_FAIL( "XMLFilterBase::writeCustomProperties unsupported value type!" );
+42 -18
View File
@@ -1572,8 +1572,9 @@ bool Converter::convertDuration(util::Duration& rDuration,
return convertDurationHelper(rDuration, o3tl::trim(rString));
}
template<typename TStringBuffer>
static void
lcl_AppendTimezone(OUStringBuffer & i_rBuffer, int const nOffset)
lcl_AppendTimezone(TStringBuffer & i_rBuffer, int const nOffset)
{
if (0 == nOffset)
{
@@ -1618,18 +1619,19 @@ void Converter::convertDate(
convertDateTime(i_rBuffer, dt, pTimeZoneOffset);
}
template<typename TStringBuffer, typename TString>
static void convertTime(
OUStringBuffer& i_rBuffer,
TStringBuffer& i_rBuffer,
const css::util::DateTime& i_rDateTime)
{
if (i_rDateTime.Hours < 10) {
i_rBuffer.append('0');
}
i_rBuffer.append( OUString::number(static_cast<sal_Int32>(i_rDateTime.Hours)) + ":");
i_rBuffer.append( TString::number(static_cast<sal_Int32>(i_rDateTime.Hours)) + ":");
if (i_rDateTime.Minutes < 10) {
i_rBuffer.append('0');
}
i_rBuffer.append( OUString::number(static_cast<sal_Int32>(i_rDateTime.Minutes) ) + ":");
i_rBuffer.append( TString::number(static_cast<sal_Int32>(i_rDateTime.Minutes) ) + ":");
if (i_rDateTime.Seconds < 10) {
i_rBuffer.append('0');
}
@@ -1637,16 +1639,17 @@ static void convertTime(
if (i_rDateTime.NanoSeconds > 0) {
OSL_ENSURE(i_rDateTime.NanoSeconds < 1000000000,"NanoSeconds cannot be more than 999 999 999");
i_rBuffer.append('.');
std::ostringstream ostr;
ostr.fill('0');
ostr.width(9);
ostr << i_rDateTime.NanoSeconds;
i_rBuffer.appendAscii(ostr.str().c_str());
// pad to 9 characters length
auto sNanoStr = TString::number(i_rDateTime.NanoSeconds);
for (int i=0; i < 9 - sNanoStr.length; i++)
i_rBuffer.append('0');
i_rBuffer.append(sNanoStr);
}
}
template<typename TStringBuffer>
static void convertTimeZone(
OUStringBuffer& i_rBuffer,
TStringBuffer& i_rBuffer,
const css::util::DateTime& i_rDateTime,
sal_Int16 const* pTimeZoneOffset)
{
@@ -1669,7 +1672,7 @@ void Converter::convertTimeOrDateTime(
i_rDateTime.Month < 1 || i_rDateTime.Month > 12 ||
i_rDateTime.Day < 1 || i_rDateTime.Day > 31)
{
convertTime(i_rBuffer, i_rDateTime);
convertTime<OUStringBuffer, OUString>(i_rBuffer, i_rDateTime);
convertTimeZone(i_rBuffer, i_rDateTime, nullptr);
}
else
@@ -1679,14 +1682,15 @@ void Converter::convertTimeOrDateTime(
}
/** convert util::DateTime to ISO "date" or "dateTime" string */
void Converter::convertDateTime(
OUStringBuffer& i_rBuffer,
template<typename TStringBuffer, typename TString, typename TStringChar>
static void lcl_convertDateTime(
TStringBuffer& i_rBuffer,
const css::util::DateTime& i_rDateTime,
sal_Int16 const*const pTimeZoneOffset,
bool i_bAddTimeIf0AM )
{
const sal_Unicode dash('-');
const sal_Unicode zero('0');
const char dash('-');
const char zero('0');
sal_Int32 const nYear(abs(i_rDateTime.Year));
if (i_rDateTime.Year < 0) {
@@ -1701,11 +1705,11 @@ void Converter::convertDateTime(
if (nYear < 10) {
i_rBuffer.append(zero);
}
i_rBuffer.append( OUString::number(nYear) + OUStringChar(dash) );
i_rBuffer.append( TString::number(nYear) + TStringChar(dash) );
if( i_rDateTime.Month < 10 ) {
i_rBuffer.append(zero);
}
i_rBuffer.append( OUString::number(i_rDateTime.Month) + OUStringChar(dash) );
i_rBuffer.append( TString::number(i_rDateTime.Month) + TStringChar(dash) );
if( i_rDateTime.Day < 10 ) {
i_rBuffer.append(zero);
}
@@ -1717,12 +1721,32 @@ void Converter::convertDateTime(
i_bAddTimeIf0AM )
{
i_rBuffer.append('T');
convertTime(i_rBuffer, i_rDateTime);
convertTime<TStringBuffer, TString>(i_rBuffer, i_rDateTime);
}
convertTimeZone(i_rBuffer, i_rDateTime, pTimeZoneOffset);
}
/** convert util::DateTime to ISO "date" or "dateTime" string */
void Converter::convertDateTime(
OUStringBuffer& i_rBuffer,
const css::util::DateTime& i_rDateTime,
sal_Int16 const*const pTimeZoneOffset,
bool i_bAddTimeIf0AM )
{
lcl_convertDateTime<OUStringBuffer, OUString, OUStringChar>(i_rBuffer, i_rDateTime, pTimeZoneOffset, i_bAddTimeIf0AM);
}
/** convert util::DateTime to ISO "date" or "dateTime" string */
void Converter::convertDateTime(
OStringBuffer& i_rBuffer,
const css::util::DateTime& i_rDateTime,
sal_Int16 const*const pTimeZoneOffset,
bool i_bAddTimeIf0AM )
{
lcl_convertDateTime<OStringBuffer, OString, OStringChar>(i_rBuffer, i_rDateTime, pTimeZoneOffset, i_bAddTimeIf0AM);
}
/** convert ISO "date" or "dateTime" string to util::DateTime */
bool Converter::parseDateTime( util::DateTime& rDateTime,
std::u16string_view rString )