1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: elementparser.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
34 #include "elementparser.hxx"
35 #include "xmlstrings.hxx"
36 #include "typeconverter.hxx"
38 #include <com/sun/star/configuration/backend/SchemaAttribute.hpp>
39 #include <com/sun/star/configuration/backend/NodeAttribute.hpp>
41 #include <rtl/ustrbuf.hxx>
43 // -----------------------------------------------------------------------------
47 // -----------------------------------------------------------------------------
50 // -----------------------------------------------------------------------------
51 namespace uno
= ::com::sun::star::uno
;
52 namespace sax
= ::com::sun::star::xml::sax
;
53 // -----------------------------------------------------------------------------
57 sal_Int16
impl_getIndexByName(uno::Reference
< sax::XAttributeList
> const& xAttribs
, rtl::OUString
const& aAttributeName
)
59 OSL_PRECOND( xAttribs
.is(), "ERROR: NULL Attribute list");
61 sal_Int16 nIndex
= xAttribs
->getLength();
65 if (xAttribs
->getNameByIndex(nIndex
).equals(aAttributeName
))
68 // nIndex == -1 if not found
72 // -----------------------------------------------------------------------------
75 bool impl_maybeGetAttribute(uno::Reference
< sax::XAttributeList
> const& xAttribs
, rtl::OUString
const& aAttributeName
, /* OUT */ rtl::OUString
& rAttributeValue
)
77 OSL_PRECOND( xAttribs
.is(), "ERROR: NULL Attribute list");
79 rtl::OUString aValue
= xAttribs
->getValueByName(aAttributeName
);
80 if( aValue
.getLength()!=0)
82 rAttributeValue
= aValue
;
87 // -----------------------------------------------------------------------------
89 /// retrieve the (almost) complete information for an element
90 ElementInfo
ElementParser::parseElementInfo(rtl::OUString
const& _sTag
, uno::Reference
< sax::XAttributeList
> const& _xAttribs
) const
92 ElementType::Enum aType
= this->getNodeType(_sTag
,_xAttribs
);
94 ElementInfo
aInfo( this->getName(_sTag
,_xAttribs
,aType
), aType
);
96 aInfo
.op
= this->getOperation(_xAttribs
,aType
);
97 aInfo
.flags
= this->getNodeFlags(_xAttribs
,aType
);
101 // -----------------------------------------------------------------------------
103 ElementType::Enum
ElementParser::getNodeType(rtl::OUString
const& _sElementName
, uno::Reference
< sax::XAttributeList
> const& _xAttribs
) const
106 OSL_PRECOND( _xAttribs
.is(), "ERROR: NULL Attribute list");
108 // todo: make this use a table, if necessary
109 ElementType::Enum eResult
= ElementType::unknown
;
110 if (_sElementName
.equals(TAG_VALUE
))
111 eResult
= ElementType::value
;
113 else if (_sElementName
.equals(TAG_PROP
))
114 eResult
= ElementType::property
;
116 else if (_sElementName
.equals(TAG_NODE
))
117 eResult
= ElementType::node
;
119 else if (_sElementName
.equals(TAG_GROUP
))
120 eResult
= ElementType::group
;
122 else if (_sElementName
.equals(TAG_SET
))
123 eResult
= ElementType::set
;
125 else if (_sElementName
.equals(TAG_INSTANCE
))
126 eResult
= ElementType::instance
;
128 else if (_sElementName
.equals(TAG_ITEMTYPE
))
129 eResult
= ElementType::item_type
;
131 else if (_sElementName
.equals(TAG_IMPORT
))
132 eResult
= ElementType::import
;
134 else if (_sElementName
.equals(TAG_LAYER
))
135 eResult
= ElementType::layer
;
137 else if (_sElementName
.equals(TAG_SCHEMA
))
138 eResult
= ElementType::schema
;
140 else if (_sElementName
.equals(TAG_COMPONENT
))
141 eResult
= ElementType::component
;
143 else if (_sElementName
.equals(TAG_TEMPLATES
))
144 eResult
= ElementType::templates
;
146 else if (_sElementName
.equals(TAG_USES
))
147 eResult
= ElementType::uses
;
149 // #109668# maintain support for old tag on load
150 else if (_sElementName
.equals(DEPRECATED_TAG_LAYER
))
152 logger().warning("Layer starts with invalid root tag \"oor:node\". Use \"oor:component-data\" instead.",
153 "getNodeType()","configmgr::xml::ElementParser");
154 eResult
= ElementType::layer
;
158 eResult
= ElementType::other
;
162 // -----------------------------------------------------------------------------
164 /// takes the node name from either an attribute or the element name
165 rtl::OUString
ElementParser::getName(rtl::OUString
const& _sElementName
, uno::Reference
< sax::XAttributeList
> const& _xAttribs
, ElementType::Enum _eType
) const
168 rtl::OUString aPackage
;
170 bool bNameFound
= this->maybeGetAttribute(_xAttribs
, ATTR_NAME
, aName
);
171 bool bPackage
= false;
175 case ElementType::schema
:
176 bPackage
= this->maybeGetAttribute(_xAttribs
,ATTR_PACKAGE
,aPackage
);
177 OSL_ENSURE(bPackage
, "configmgr::xml::ElementParser: Found schema without package.");
180 case ElementType::layer
:
181 bPackage
= this->maybeGetAttribute(_xAttribs
,ATTR_PACKAGE
,aPackage
);
183 if (!bPackage
) // for compatibility we still support 'oor:context'
185 bPackage
= this->maybeGetAttribute(_xAttribs
,ATTR_CONTEXT
,aPackage
);
190 OSL_TRACE("configmgr::xml::ElementParser: Found obsolete layer attribute "
191 "oor:context=\"%s\" in component \"%s\".\n",
192 rtl::OUStringToOString(aPackage
,RTL_TEXTENCODING_ASCII_US
).getStr(),
193 rtl::OUStringToOString(aName
,RTL_TEXTENCODING_ASCII_US
).getStr());
197 OSL_ENSURE(bPackage
, "configmgr::xml::ElementParser: Found layer without package.");
200 case ElementType::node
:
201 case ElementType::set
:
202 case ElementType::group
:
203 case ElementType::instance
:
204 case ElementType::property
:
207 // these have no name to speak of
208 case ElementType::value
:
209 case ElementType::item_type
:
210 case ElementType::import
:
211 case ElementType::uses
:
212 case ElementType::templates
:
213 case ElementType::component
:
214 OSL_ENSURE(!bNameFound
, "Configuration Parser: Unexpected name attribute is ignored\n");
215 return _sElementName
;
217 // for unknown prefer name to
218 case ElementType::unknown
:
219 if (!bNameFound
) return _sElementName
;
221 bPackage
= this->maybeGetAttribute(_xAttribs
,ATTR_PACKAGE
,aPackage
);
225 if (!bNameFound
) return _sElementName
;
229 OSL_ENSURE(aName
.getLength(),"Found empty name tag on element");
233 static const sal_Unicode chPackageSep
= '.';
235 aName
= aPackage
.concat(rtl::OUString(&chPackageSep
,1)).concat(aName
);
239 OSL_ENSURE(!this->maybeGetAttribute(_xAttribs
,ATTR_PACKAGE
,aPackage
),
240 "configmgr::xml::ElementParser: Found unexpected 'oor:package' on inner or unknown node." );
245 // -----------------------------------------------------------------------------
247 Operation::Enum
ElementParser::getOperation(uno::Reference
< sax::XAttributeList
> const& xAttribs
,ElementType::Enum _eType
) const
249 rtl::OUString sOpName
;
250 if ((_eType
!= ElementType::property
) && (_eType
!=ElementType::node
))
252 return Operation::none
;
255 if ( !this->maybeGetAttribute(xAttribs
,ATTR_OPERATION
, sOpName
) )
256 return Operation::none
;
258 if (sOpName
.equals(OPERATION_MODIFY
))
259 return Operation::modify
;
261 else if (sOpName
.equals(OPERATION_REPLACE
))
262 return Operation::replace
;
263 else if (sOpName
.equals(OPERATION_FUSE
))
264 return Operation::fuse
;
266 else if (sOpName
.equals(OPERATION_REMOVE
))
267 return Operation::remove
;
269 else if (sOpName
.equals(OPERATION_CLEAR
))
270 return Operation::clear
;
273 return Operation::unknown
;
275 // -----------------------------------------------------------------------------
278 /// retrieve the locale stored in the attribute list
279 bool ElementParser::getLanguage(uno::Reference
< sax::XAttributeList
> const& xAttribs
, rtl::OUString
& _rsLanguage
) const
281 return this->maybeGetAttribute(xAttribs
, EXT_ATTR_LANGUAGE
, _rsLanguage
);
283 // -----------------------------------------------------------------------------
285 /// reads attributes for nodes from the attribute list
286 sal_Int16
ElementParser::getNodeFlags(uno::Reference
< sax::XAttributeList
> const& xAttribs
,ElementType::Enum _eType
) const
288 namespace NodeAttribute
= ::com::sun::star::configuration::backend::NodeAttribute
;
289 namespace SchemaAttribute
= ::com::sun::star::configuration::backend::SchemaAttribute
;
293 sal_Int16 aResult
= 0;
297 case ElementType::property
:
298 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_NULLABLE
, bValue
) && ! bValue
)
299 aResult
|= SchemaAttribute::REQUIRED
;
300 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_LOCALIZED
, bValue
) && bValue
)
301 aResult
|= SchemaAttribute::LOCALIZED
;
302 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_READONLY
, bValue
) && bValue
)
303 aResult
|= NodeAttribute::READONLY
;
304 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_FINALIZED
, bValue
) && bValue
)
305 aResult
|= NodeAttribute::FINALIZED
;
308 case ElementType::node
:
309 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_FINALIZED
, bValue
) && bValue
)
310 aResult
|= NodeAttribute::FINALIZED
;
311 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_MANDATORY
, bValue
) && bValue
)
312 aResult
|= NodeAttribute::MANDATORY
;
313 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_READONLY
, bValue
) && bValue
)
314 aResult
|= NodeAttribute::READONLY
;
317 case ElementType::group
:
318 case ElementType::set
:
319 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_EXTENSIBLE
, bValue
) && bValue
)
320 aResult
|= SchemaAttribute::EXTENSIBLE
;
323 case ElementType::layer
:
324 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_READONLY
, bValue
) && bValue
)
325 aResult
|= NodeAttribute::READONLY
;
326 if (this->maybeGetAttribute(xAttribs
, ATTR_FLAG_FINALIZED
, bValue
) && bValue
)
327 aResult
|= NodeAttribute::FINALIZED
;
336 // -----------------------------------------------------------------------------
338 void badValueType(Logger
const & logger
, sal_Char
const * _pMsg
, rtl::OUString
const & _sType
)
340 rtl::OUStringBuffer sMessageBuf
;
341 sMessageBuf
.appendAscii( "Configuration XML parser: Bad value type attribute: " );
342 if (_pMsg
) sMessageBuf
.appendAscii(_pMsg
);
344 const sal_Unicode kQuote
= '"';
345 sMessageBuf
.append(kQuote
).append(_sType
).append(kQuote
);
347 rtl::OUString
const sMessage
= sMessageBuf
.makeStringAndClear();
348 logger
.error(sMessage
);
349 throw ElementParser::BadValueType(sMessage
);
351 // -----------------------------------------------------------------------------
354 sal_Bool
matchNsPrefix(rtl::OUString
const & _sString
, rtl::OUString
const & _sPrefix
)
356 return _sString
.match(_sPrefix
) &&
357 _sString
.getStr()[_sPrefix
.getLength()] == k_NS_SEPARATOR
;
359 // -----------------------------------------------------------------------------
362 sal_Bool
matchSuffix(rtl::OUString
const & _sString
, rtl::OUString
const & _sSuffix
)
364 sal_Int32 nSuffixStart
= _sString
.getLength() - _sSuffix
.getLength();
365 if (nSuffixStart
< 0)
368 return _sString
.match(_sSuffix
,nSuffixStart
);
370 // -----------------------------------------------------------------------------
373 rtl::OUString
stripNsPrefix(rtl::OUString
const & _sString
, rtl::OUString
const & _sPrefix
)
375 OSL_ASSERT( matchNsPrefix(_sString
,_sPrefix
) );
377 return _sString
.copy(_sPrefix
.getLength() + 1);
379 // -----------------------------------------------------------------------------
382 rtl::OUString
stripSuffix(rtl::OUString
const & _sString
, rtl::OUString
const & _sSuffix
)
384 OSL_ASSERT( matchSuffix(_sString
,_sSuffix
) );
386 sal_Int32 nSuffixStart
= _sString
.getLength() - _sSuffix
.getLength();
388 return _sString
.copy(0,nSuffixStart
);
390 // -----------------------------------------------------------------------------
393 rtl::OUString
stripTypeName(Logger
const & logger
, rtl::OUString
const & _sString
, rtl::OUString
const & _sPrefix
)
395 if ( matchNsPrefix(_sString
,_sPrefix
))
396 return stripNsPrefix(_sString
, _sPrefix
);
398 badValueType(logger
, "Missing expected namespace prefix on type name: ", _sString
);
402 // -----------------------------------------------------------------------------
404 uno::Type
xmlToScalarType(const rtl::OUString
& _rType
)
408 if (_rType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_BOOLEAN
))
409 aRet
= ::getBooleanCppuType();
411 else if(_rType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_SHORT
))
412 aRet
= ::getCppuType(static_cast<sal_Int16
const*>(0));
414 else if(_rType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_INT
))
415 aRet
= ::getCppuType(static_cast<sal_Int32
const*>(0));
417 else if(_rType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_LONG
))
418 aRet
= ::getCppuType(static_cast<sal_Int64
const*>(0));
420 else if(_rType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_DOUBLE
))
421 aRet
= ::getCppuType(static_cast< double const*>(0));
423 else if(_rType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_STRING
))
424 aRet
= ::getCppuType(static_cast<rtl::OUString
const*>(0));
426 else if(_rType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_BINARY
))
427 aRet
= ::getCppuType(static_cast<uno::Sequence
<sal_Int8
> const*>(0));
429 else if(_rType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_ANY
))
430 aRet
= ::getCppuType(static_cast<uno::Any
const*>(0));
433 OSL_ENSURE(false,"Cannot parse: Unknown value type");
437 // -----------------------------------------------------------------------------
438 uno::Type
xmlToListType(const rtl::OUString
& _aElementType
)
442 if (_aElementType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_BOOLEAN
))
443 aRet
= ::getCppuType(static_cast<uno::Sequence
<sal_Bool
> const*>(0));
445 else if(_aElementType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_SHORT
))
446 aRet
= ::getCppuType(static_cast<uno::Sequence
<sal_Int16
> const*>(0));
448 else if(_aElementType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_INT
))
449 aRet
= ::getCppuType(static_cast<uno::Sequence
<sal_Int32
> const*>(0));
451 else if(_aElementType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_LONG
))
452 aRet
= ::getCppuType(static_cast<uno::Sequence
<sal_Int64
> const*>(0));
454 else if(_aElementType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_DOUBLE
))
455 aRet
= ::getCppuType(static_cast<uno::Sequence
<double> const*>(0));
457 else if(_aElementType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_STRING
))
458 aRet
= ::getCppuType(static_cast<uno::Sequence
<rtl::OUString
> const*>(0));
460 else if(_aElementType
.equalsIgnoreAsciiCaseAscii(VALUETYPE_BINARY
))
461 aRet
= ::getCppuType(static_cast<uno::Sequence
<uno::Sequence
<sal_Int8
> > const*>(0));
464 OSL_ENSURE(false,"Cannot parse: Unknown list value type");
468 // -----------------------------------------------------------------------------
469 /// retrieve data type of a property,
470 uno::Type
ElementParser::getPropertyValueType(uno::Reference
< sax::XAttributeList
> const& xAttribs
) const
472 rtl::OUString sTypeName
;
473 if (!this->maybeGetAttribute(xAttribs
, ATTR_VALUETYPE
, sTypeName
))
474 return uno::Type(); // => VOID
478 // valuetype names are either 'xs:<type>' or 'oor:<type>' or 'oor:<type>-list'
479 if (matchSuffix(sTypeName
,VALUETYPE_LIST_SUFFIX
))
481 rtl::OUString sBasicName
= stripTypeName( mLogger
, stripSuffix(sTypeName
,VALUETYPE_LIST_SUFFIX
), NS_PREFIX_OOR
);
483 aType
= xmlToListType(sBasicName
);
487 rtl::OUString sPrefix
= matchNsPrefix(sTypeName
,NS_PREFIX_OOR
) ? rtl::OUString( NS_PREFIX_OOR
) : rtl::OUString( NS_PREFIX_XS
);
489 rtl::OUString sBasicName
= stripTypeName( mLogger
, sTypeName
, sPrefix
);
491 aType
= xmlToScalarType(sBasicName
);
494 if (aType
== uno::Type())
495 badValueType(mLogger
,"Unknown type name: ", sTypeName
);
499 // -----------------------------------------------------------------------------
501 /// retrieve element type and associated module name of a set,
502 bool ElementParser::getSetElementType(uno::Reference
< sax::XAttributeList
> const& xAttribs
, rtl::OUString
& aElementType
, rtl::OUString
& aElementTypeModule
) const
504 if (!this->maybeGetAttribute(xAttribs
, ATTR_ITEMTYPE
, aElementType
))
507 maybeGetAttribute(xAttribs
, ATTR_ITEMTYPECOMPONENT
, aElementTypeModule
);
511 // -----------------------------------------------------------------------------
513 /// retrieve instance type and associated module name of a set,
514 bool ElementParser::getInstanceType(uno::Reference
< sax::XAttributeList
> const& xAttribs
, rtl::OUString
& aElementType
, rtl::OUString
& aElementTypeModule
) const
516 if (!this->maybeGetAttribute(xAttribs
, ATTR_ITEMTYPE
, aElementType
))
519 maybeGetAttribute(xAttribs
, ATTR_ITEMTYPECOMPONENT
, aElementTypeModule
);
523 // -----------------------------------------------------------------------------
525 /// retrieve the component for an import or uses element,
526 bool ElementParser::getImportComponent(uno::Reference
< sax::XAttributeList
> const& xAttribs
, rtl::OUString
& _rsComponent
) const
528 return this->maybeGetAttribute(xAttribs
, ATTR_COMPONENT
, _rsComponent
);
530 // -----------------------------------------------------------------------------
532 /// reads attributes for values from the attribute list
533 bool ElementParser::isNull(uno::Reference
< sax::XAttributeList
> const& _xAttribs
) const
536 return maybeGetAttribute(_xAttribs
, EXT_ATTR_NULL
, bNull
) && bNull
;
538 // -----------------------------------------------------------------------------
540 /// reads attributes for values from the attribute list
541 rtl::OUString
ElementParser::getSeparator(uno::Reference
< sax::XAttributeList
> const& _xAttribs
) const
543 rtl::OUString aSeparator
;
544 maybeGetAttribute(_xAttribs
, ATTR_VALUESEPARATOR
, aSeparator
);
547 // -----------------------------------------------------------------------------
549 // low-level internal methods
550 /// checks for presence of a boolean attribute and assigns its value if it exists (and is a bool)
551 bool ElementParser::maybeGetAttribute(uno::Reference
< sax::XAttributeList
> const& xAttribs
, rtl::OUString
const& aAttributeName
, bool& rAttributeValue
) const
553 rtl::OUString sAttribute
;
555 if ( !this->maybeGetAttribute(xAttribs
, aAttributeName
, sAttribute
) )
560 else if (sAttribute
.equals(ATTR_VALUE_TRUE
))
561 rAttributeValue
= true; // will return true
563 else if (sAttribute
.equals(ATTR_VALUE_FALSE
))
564 rAttributeValue
= false; // will return true
568 OSL_ENSURE(sAttribute
.getLength() == 0, "Invalid text found in boolean attribute");
574 // -----------------------------------------------------------------------------
576 /// checks for presence of an attribute and assigns its value if it exists
577 bool ElementParser::maybeGetAttribute(uno::Reference
< sax::XAttributeList
> const& xAttribs
, rtl::OUString
const& aAttributeName
, rtl::OUString
& rAttributeValue
) const
579 return xAttribs
.is() && impl_maybeGetAttribute(xAttribs
, aAttributeName
, rAttributeValue
);
582 // -----------------------------------------------------------------------------