LibreOffice Module xmloff (master) 1
propertyimport.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <cmath>
23
24#include "propertyimport.hxx"
25
27
28#include <utility>
29#include <xmloff/xmlimp.hxx>
30#include <xmloff/xmluconv.hxx>
32#include <o3tl/temporary.hxx>
33#include <osl/diagnose.h>
34#include <sal/log.hxx>
37#include <tools/date.hxx>
38#include <tools/time.hxx>
39#include <com/sun/star/util/Date.hpp>
40#include <com/sun/star/util/Time.hpp>
41#include <com/sun/star/util/DateTime.hpp>
42#include <unotools/datetime.hxx>
43#include <rtl/strbuf.hxx>
44
45using namespace ::xmloff::token;
46
47namespace xmloff
48{
49
50 using namespace ::com::sun::star::uno;
51 using namespace ::com::sun::star::beans;
52 using namespace ::com::sun::star::xml;
53 using ::com::sun::star::xml::sax::XFastAttributeList;
54
55 // NO using namespace ...util !!!
56 // need a tools Date/Time/DateTime below, which would conflict with the uno types then
57
58#define TYPE_DATE 1
59#define TYPE_TIME 2
60#define TYPE_DATETIME 3
61
62//= PropertyConversion
63namespace
64{
65 css::util::Time lcl_getTime(double _nValue)
66 {
67 css::util::Time aTime;
68 sal_uInt64 nIntValue = static_cast<sal_uInt64>(_nValue * ::tools::Time::nanoSecPerDay);
69 aTime.NanoSeconds = nIntValue % ::tools::Time::nanoSecPerSec;
71 aTime.Seconds = nIntValue % ::tools::Time::secondPerMinute;
73 aTime.Minutes = nIntValue % ::tools::Time::minutePerHour;
75 OSL_ENSURE(nIntValue < 24, "lcl_getTime: more than a day?");
76 aTime.Hours = nIntValue;
77
78 return aTime;
79 }
80
81 css::util::Date lcl_getDate( double _nValue )
82 {
83 Date aToolsDate(static_cast<sal_uInt32>(_nValue));
84 css::util::Date aDate;
85 ::utl::typeConvert(aToolsDate, aDate);
86 return aDate;
87 }
88}
89
90Any PropertyConversion::convertString( const css::uno::Type& _rExpectedType,
91 const OUString& _rReadCharacters, const SvXMLEnumMapEntry<sal_uInt16>* _pEnumMap, const bool _bInvertBoolean )
92{
93 Any aReturn;
94 bool bEnumAsInt = false;
95 switch (_rExpectedType.getTypeClass())
96 {
97 case TypeClass_BOOLEAN: // sal_Bool
98 {
99 bool bValue;
100 bool bSuccess =
101 ::sax::Converter::convertBool(bValue, _rReadCharacters);
102 OSL_ENSURE(bSuccess,
103 OStringBuffer("PropertyConversion::convertString: could not convert \"" +
104 OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) +
105 "\" into a boolean!").getStr());
106 aReturn <<= (_bInvertBoolean ? !bValue : bValue);
107 }
108 break;
109 case TypeClass_SHORT: // sal_Int16
110 case TypeClass_LONG: // sal_Int32
111 if (!_pEnumMap)
112 { // it's a real int32/16 property
113 sal_Int32 nValue(0);
114 bool bSuccess =
115 ::sax::Converter::convertNumber(nValue, _rReadCharacters);
116 OSL_ENSURE(bSuccess,
117 OStringBuffer("PropertyConversion::convertString: could not convert \"" +
118 OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) +
119 "\" into an integer!").getStr());
120 if (TypeClass_SHORT == _rExpectedType.getTypeClass())
121 aReturn <<= static_cast<sal_Int16>(nValue);
122 else
123 aReturn <<= nValue;
124 break;
125 }
126 bEnumAsInt = true;
127 [[fallthrough]];
128 case TypeClass_ENUM:
129 {
130 sal_uInt16 nEnumValue(0);
131 bool bSuccess = SvXMLUnitConverter::convertEnum(nEnumValue, _rReadCharacters, _pEnumMap);
132 OSL_ENSURE(bSuccess, "PropertyConversion::convertString: could not convert to an enum value!");
133
134 if (bEnumAsInt)
135 if (TypeClass_SHORT == _rExpectedType.getTypeClass())
136 aReturn <<= static_cast<sal_Int16>(nEnumValue);
137 else
138 aReturn <<= static_cast<sal_Int32>(nEnumValue);
139 else
140 aReturn = ::cppu::int2enum(static_cast<sal_Int32>(nEnumValue), _rExpectedType);
141 }
142 break;
143 case TypeClass_HYPER:
144 {
145 OSL_FAIL("PropertyConversion::convertString: 64-bit integers not implemented yet!");
146 }
147 break;
148 case TypeClass_DOUBLE:
149 {
150 double nValue;
151 bool bSuccess =
152 ::sax::Converter::convertDouble(nValue, _rReadCharacters);
153 OSL_ENSURE(bSuccess,
154 OStringBuffer(OString::Concat("PropertyConversion::convertString: could not convert \"") +
155 OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) +
156 "\" into a double!").getStr());
157 aReturn <<= nValue;
158 }
159 break;
160 case TypeClass_STRING:
161 aReturn <<= _rReadCharacters;
162 break;
163 case TypeClass_STRUCT:
164 {
165 sal_Int32 nType = 0;
166 if ( _rExpectedType.equals( ::cppu::UnoType< css::util::Date >::get() ) )
168 else if ( _rExpectedType.equals( ::cppu::UnoType< css::util::Time >::get() ) )
170 else if ( _rExpectedType.equals( ::cppu::UnoType< css::util::DateTime >::get() ) )
172
173 if ( nType )
174 {
175 // first extract the double
176 double nValue = 0;
177 bool bSuccess =
178 ::sax::Converter::convertDouble(nValue, _rReadCharacters);
179 OSL_ENSURE(bSuccess,
180 OStringBuffer("PropertyConversion::convertString: could not convert \"" +
181 OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) +
182 "\" into a double!").getStr());
183
184 // then convert it into the target type
185 switch (nType)
186 {
187 case TYPE_DATE:
188 {
189 OSL_ENSURE(std::modf(nValue, &o3tl::temporary(double())) == 0,
190 "PropertyConversion::convertString: a Date value with a fractional part?");
191 aReturn <<= lcl_getDate(nValue);
192 }
193 break;
194 case TYPE_TIME:
195 {
196 OSL_ENSURE((static_cast<sal_uInt32>(nValue)) == 0,
197 "PropertyConversion::convertString: a tools::Time value with more than a fractional part?");
198 aReturn <<= lcl_getTime(nValue);
199 }
200 break;
201 case TYPE_DATETIME:
202 {
203 css::util::Time aTime = lcl_getTime(nValue);
204 css::util::Date aDate = lcl_getDate(nValue);
205
206 css::util::DateTime aDateTime;
207 aDateTime.NanoSeconds = aTime.NanoSeconds;
208 aDateTime.Seconds = aTime.Seconds;
209 aDateTime.Minutes = aTime.Minutes;
210 aDateTime.Hours = aTime.Hours;
211 aDateTime.Day = aDate.Day;
212 aDateTime.Month = aDate.Month;
213 aDateTime.Year = aDate.Year;
214 aReturn <<= aDateTime;
215 }
216 break;
217 }
218 }
219 else
220 OSL_FAIL("PropertyConversion::convertString: unsupported property type!");
221 }
222 break;
223 default:
224 OSL_FAIL("PropertyConversion::convertString: invalid type class!");
225 }
226
227 return aReturn;
228}
229
231{
232 Type aUnoType( cppu::UnoType<void>::get() );
233
234 static std::map< OUString, css::uno::Type > s_aTypeNameMap
235 {
237 // Not a copy paste error, quotation from:
238 // http://nabble.documentfoundation.org/Question-unoType-for-getXmlToken-dbaccess-reportdesign-module-tp4109071p4109116.html
239 // all numeric types (including the UNO double)
240 // consistently map to XML_FLOAT, so taking the extra precision from the
241 // C++ type "float" to "double" makes absolute sense
245 };
246
247 const std::map< OUString, css::uno::Type >::iterator aTypePos = s_aTypeNameMap.find( _rType );
248 OSL_ENSURE( s_aTypeNameMap.end() != aTypePos, "PropertyConversion::xmlTypeToUnoType: invalid property name!" );
249 if ( s_aTypeNameMap.end() != aTypePos )
250 aUnoType = aTypePos->second;
251
252 return aUnoType;
253}
254
255//= OPropertyImport
257 :SvXMLImportContext(_rImport.getGlobalContext())
258 ,m_rContext(_rImport)
259 ,m_bTrackAttributes(false)
260{
261}
262
263css::uno::Reference< css::xml::sax::XFastContextHandler > OPropertyImport::createFastChildContext(
264 sal_Int32 nElement,
265 const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ )
266{
267 if( (nElement & TOKEN_MASK) == token::XML_PROPERTIES )
268 {
270 }
271 else
272 SAL_WARN("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
273 return nullptr;
274}
275
276void OPropertyImport::startFastElement(sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& xAttrList)
277{
278
279 // assume the 'worst' case: all attributes describe properties. This should save our property array
280 // some reallocs
282
283 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
284 {
285 handleAttribute(aIter.getToken(), aIter.toString());
286
288 m_aEncounteredAttributes.insert(aIter.getToken() & TOKEN_MASK);
289 }
290
291 // TODO: create PropertyValues for all the attributes which were not present, because they were implied
292 // this is necessary as soon as we have properties where the XML default is different from the property
293 // default
294}
295
296bool OPropertyImport::encounteredAttribute(sal_Int32 nAttributeToken) const
297{
298 OSL_ENSURE(m_bTrackAttributes, "OPropertyImport::encounteredAttribute: attribute tracking not enabled!");
300}
301
302void OPropertyImport::characters(const OUString& _rChars )
303{
304 // ignore them (should be whitespace only)
305 OSL_ENSURE(o3tl::trim(_rChars).empty(), "OPropertyImport::Characters: non-whitespace characters!");
306}
307
308bool OPropertyImport::handleAttribute(sal_Int32 nAttributeToken, const OUString& _rValue)
309{
311 if (pProperty)
312 {
313 // create and store a new PropertyValue
314 PropertyValue aNewValue;
315 aNewValue.Name = pProperty->sPropertyName;
316
317 // convert the value string into the target type
318 if ((nAttributeToken & TOKEN_MASK) == token::XML_HREF)
319 {
320 aNewValue.Value <<= m_rContext.getGlobalContext().GetAbsoluteReference(_rValue);
321 }
322 else
323 {
324 aNewValue.Value = PropertyConversion::convertString(
325 pProperty->aPropertyType, _rValue, pProperty->pEnumMap,
326 pProperty->bInverseSemantics);
327 }
328 implPushBackPropertyValue( aNewValue );
329 return true;
330 }
331 if ((nAttributeToken & TOKEN_MASK) != token::XML_TYPE) // xlink:type is valid but ignored for <form:form>
332 {
333 SAL_WARN( "xmloff", "OPropertyImport::handleAttribute: Can't handle "
334 << SvXMLImport::getPrefixAndNameFromToken(nAttributeToken) << "=" << _rValue );
335 return false;
336 }
337 return true;
338}
339
340//= OPropertyElementsContext
342 OPropertyImportRef _xPropertyImporter)
343 :SvXMLImportContext(_rImport)
344 ,m_xPropertyImporter(std::move(_xPropertyImporter))
345{
346}
347
348css::uno::Reference< css::xml::sax::XFastContextHandler > OPropertyElementsContext::createFastChildContext(
349 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
350{
351 if( (nElement & TOKEN_MASK) == XML_PROPERTY )
352 {
354 }
355 else if( (nElement & TOKEN_MASK) == XML_LIST_PROPERTY )
356 {
358 }
359 return nullptr;
360}
361
362#if OSL_DEBUG_LEVEL > 0
364 sal_Int32 /*nElement*/,
365 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
366 {
367 OSL_ENSURE(0 == xAttrList->getFastAttributes().getLength(), "OPropertyElementsContext::StartElement: the form:properties element should not have attributes!");
368 }
369
370 void OPropertyElementsContext::characters(const OUString& _rChars)
371 {
372 OSL_ENSURE(o3tl::trim(_rChars).empty(), "OPropertyElementsContext::Characters: non-whitespace characters detected!");
373 }
374#endif
375
376//= OSinglePropertyContext
378 OPropertyImportRef _xPropertyImporter)
379 :SvXMLImportContext(_rImport)
380 ,m_xPropertyImporter(std::move(_xPropertyImporter))
381{
382}
383
385 sal_Int32 /*nElement*/,
386 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
387{
388 css::beans::PropertyValue aPropValue; // the property the instance imports currently
389 css::uno::Type aPropType; // the type of the property the instance imports currently
390
391 OUString sType, sValue;
392 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
393 {
394 switch (aIter.getToken())
395 {
397 aPropValue.Name = aIter.toString();
398 break;
400 sType = aIter.toString();
401 break;
405 sValue = aIter.toString();
406 break;
407 default:
408 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
409 }
410 }
411
412 // the name of the property
413 OSL_ENSURE(!aPropValue.Name.isEmpty(), "OSinglePropertyContext::StartElement: invalid property name!");
414
415 // needs to be translated into a css::uno::Type
417 if( TypeClass_VOID == aPropType.getTypeClass() )
418 {
419 aPropValue.Value = Any();
420 }
421 else
422 {
423 aPropValue.Value =
425 sValue);
426 }
427
428 // now that we finally have our property value, add it to our parent object
429 if( !aPropValue.Name.isEmpty() )
430 m_xPropertyImporter->implPushBackGenericPropertyValue(aPropValue);
431}
432
433//= OListPropertyContext
435 OPropertyImportRef _rPropertyImporter )
436 :SvXMLImportContext( _rImport )
437 ,m_xPropertyImporter(std::move( _rPropertyImporter ))
438{
439}
440
442 sal_Int32 /*nElement*/,
443 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
444{
445 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
446 {
447 switch (aIter.getToken())
448 {
450 m_sPropertyName = aIter.toString();
451 break;
453 m_sPropertyType = aIter.toString();
454 break;
455 default:
456 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
457 }
458 }
459}
460
462{
463 OSL_ENSURE( !m_sPropertyName.isEmpty() && !m_sPropertyType.isEmpty(),
464 "OListPropertyContext::EndElement: no property name or type!" );
465
466 if ( m_sPropertyName.isEmpty() || m_sPropertyType.isEmpty() )
467 return;
468
469 Sequence< Any > aListElements( m_aListValues.size() );
470 Any* pListElement = aListElements.getArray();
472 for ( const auto& rListValue : m_aListValues )
473 {
474 *pListElement = PropertyConversion::convertString( aType, rListValue );
475 ++pListElement;
476 }
477
478 PropertyValue aSequenceValue;
479 aSequenceValue.Name = m_sPropertyName;
480 aSequenceValue.Value <<= aListElements;
481
482 m_xPropertyImporter->implPushBackGenericPropertyValue( aSequenceValue );
483}
484
485css::uno::Reference< css::xml::sax::XFastContextHandler > OListPropertyContext::createFastChildContext(
486 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
487{
488 if ( (nElement & TOKEN_MASK) == XML_LIST_VALUE )
489 {
490 m_aListValues.emplace_back();
491 return new OListValueContext( GetImport(), *m_aListValues.rbegin() );
492 }
493 return nullptr;
494}
495
496//= OListValueContext
497OListValueContext::OListValueContext( SvXMLImport& _rImport, OUString& _rListValueHolder )
498 :SvXMLImportContext( _rImport )
499 ,m_rListValueHolder( _rListValueHolder )
500{
501}
502
504 sal_Int32 /*nElement*/,
505 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
506{
507 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
508 {
509 switch(aIter.getToken())
510 {
514 m_rListValueHolder = aIter.toString();
515 break;
516 default:
517 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
518 }
519 }
520}
521
522} // namespace xmloff
523
524/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
This class deliberately does not support XWeak, to improve performance when loading large documents.
Definition: xmlictxt.hxx:48
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:60
static bool convertEnum(EnumT &rEnum, std::u16string_view rValue, const SvXMLEnumMapEntry< EnumT > *pMap)
convert string to enum using given enum map, if the enum is not found in the map, this method will re...
Definition: xmluconv.hxx:145
css::uno::Type const & get()
const_iterator find(const Value &x) const
const_iterator end() const
std::pair< const_iterator, bool > insert(Value &&x)
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
static bool convertBool(bool &rBool, std::u16string_view rString)
static const sal_Int64 minutePerHour
static const sal_Int64 nanoSecPerDay
static const sal_Int64 nanoSecPerSec
static const sal_Int64 secondPerMinute
const AttributeAssignment * getAttributeTranslation(sal_Int32 nAttributeToken)
return the AttributeAssignment which corresponds to the given attribute
OAttribute2Property & getAttributeMap()
Definition: layerimport.hxx:95
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &AttrList) override
OPropertyImportRef m_xPropertyImporter
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
::std::vector< OUString > m_aListValues
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
endFastElement is called before a context will be destructed, but after an elements context has been ...
OListPropertyContext(SvXMLImport &_rImport, OPropertyImportRef _xPropertyImporter)
OListValueContext(SvXMLImport &_rImport, OUString &_rListValueHolder)
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
helper class for importing the <form:properties> element
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
OPropertyElementsContext(SvXMLImport &_rImport, OPropertyImportRef _xPropertyImporter)
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &AttrList) override
OPropertyImportRef m_xPropertyImporter
virtual void SAL_CALL characters(const OUString &_rChars) override
This method is called for all characters that are contained in the current element.
PropertyValueArray m_aValues
void implPushBackPropertyValue(const css::beans::PropertyValue &_rProp)
virtual bool handleAttribute(sal_Int32 nElement, const OUString &_rValue)
handle one single attribute.
o3tl::sorted_vector< sal_Int32 > m_aEncounteredAttributes
OPropertyImport(OFormLayerXMLImport_Impl &_rImport)
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &AttrList) override
bool encounteredAttribute(sal_Int32 nElement) const
determine if the element imported by the object had a given attribute.
virtual void SAL_CALL characters(const OUString &_rChars) override
This method is called for all characters that are contained in the current element.
OFormLayerXMLImport_Impl & m_rContext
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &_rxAttrList) override
helper class for importing a single <form:property> element
OPropertyImportRef m_xPropertyImporter
OSinglePropertyContext(SvXMLImport &_rImport, OPropertyImportRef _xPropertyImporter)
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
static css::uno::Any convertString(const css::uno::Type &_rExpectedType, const OUString &_rReadCharacters, const SvXMLEnumMapEntry< EnumT > *_pEnumMap=nullptr)
static css::uno::Type xmlTypeToUnoType(const OUString &_rType)
sal_Int32 _nValue
sal_Int16 nValue
#define SAL_WARN(area, stream)
size
Type
FORM
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
constexpr T & temporary(T &&x)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
Handling of tokens in XML:
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
return the OUString representation for eToken
Definition: xmltoken.cxx:3541
#define TYPE_DATETIME
#define TYPE_TIME
#define TYPE_DATE
QPRO_FUNC_TYPE nType
const SvXMLEnumMapEntry< sal_uInt16 > * pEnumMap
const Reference< XComponentContext > & m_rContext
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:114
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:97
constexpr sal_Int32 TOKEN_MASK
Definition: xmlimp.hxx:94