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: basicparser.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 "basicparser.hxx"
35 #include <com/sun/star/xml/sax/SAXException.hpp>
36 #include "valuetypeconverter.hxx"
37 // -----------------------------------------------------------------------------
41 // -----------------------------------------------------------------------------
44 // -----------------------------------------------------------------------------
45 namespace uno
= ::com::sun::star::uno
;
46 namespace sax
= ::com::sun::star::xml::sax
;
47 // -----------------------------------------------------------------------------
52 uno::Reference
< script::XTypeConverter
> createTCV(uno::Reference
< uno::XComponentContext
> const & _xContext
)
54 OSL_ENSURE(_xContext
.is(),"Cannot create Parser without a Context");
56 static const rtl::OUString
k_sTCVService(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.script.Converter"));
58 uno::Reference
< lang::XMultiComponentFactory
> xSvcFactory
= _xContext
->getServiceManager();
59 return uno::Reference
< script::XTypeConverter
>::query(xSvcFactory
->createInstanceWithContext(k_sTCVService
,_xContext
));
62 // -----------------------------------------------------------------------------
64 struct BasicParser::ValueData
: ValueConverter
66 rtl::OUString content
;
70 ValueData(uno::Type
const& _aType
, uno::Reference
< script::XTypeConverter
> const & _xTCV
)
71 : ValueConverter(_aType
, _xTCV
)
78 uno::Any
convertToAny() const
80 return ValueConverter::convertToAny(this->content
);
83 rtl::OUString
toString() const
88 uno::Sequence
<rtl::OUString
> toStringList() const
90 return ValueConverter::splitStringList(this->content
);
93 void setLocalized(rtl::OUString
const & _aLocale
)
99 // -----------------------------------------------------------------------------
101 BasicParser::BasicParser(uno::Reference
< uno::XComponentContext
> const & _xContext
)
102 : m_xTypeConverter( createTCV(_xContext
) )
104 , m_aDataParser(Logger(_xContext
))
110 , m_bInProperty(false)
112 if (!m_xTypeConverter
.is())
113 throw uno::RuntimeException();
115 OSL_DEBUG_ONLY( dbgUpdateLocation() );
117 // -----------------------------------------------------------------------------
119 BasicParser::~BasicParser()
123 // -----------------------------------------------------------------------------
125 #if OSL_DEBUG_LEVEL > 0
126 void BasicParser::dbgUpdateLocation()
129 rtl::OUString dbgPublicId
, dbgSystemId
;
130 sal_Int32 dbgLineNo
, dbgColumnNo
;
131 #endif // OSL_DEBUG_LEVEL
135 dbgPublicId
= m_xLocator
->getPublicId();
136 dbgSystemId
= m_xLocator
->getSystemId();
137 dbgLineNo
= m_xLocator
->getLineNumber();
138 dbgColumnNo
= m_xLocator
->getColumnNumber();
142 dbgPublicId
= dbgSystemId
= rtl::OUString::createFromAscii("<<<unknown>>>");
143 dbgLineNo
= dbgColumnNo
= -1;
147 // -----------------------------------------------------------------------------
148 void SAL_CALL
BasicParser::startDocument( )
149 throw (sax::SAXException
, uno::RuntimeException
)
151 m_aDataParser
.reset();
152 m_aValueType
= uno::Type();
153 m_bInProperty
= false;
156 delete m_pValueData
, m_pValueData
= NULL
;
158 while (!m_aNodes
.empty()) m_aNodes
.pop();
162 OSL_DEBUG_ONLY( dbgUpdateLocation() );
164 // -----------------------------------------------------------------------------
166 void SAL_CALL
BasicParser::endDocument( ) throw (sax::SAXException
, uno::RuntimeException
)
168 OSL_DEBUG_ONLY( dbgUpdateLocation() );
170 if (!m_aNodes
.empty() || isSkipping() || isInValueData())
171 raiseParseException( "Configuration XML Parser - Invalid XML: Unexpected end of document" );
175 // -----------------------------------------------------------------------------
177 void SAL_CALL
BasicParser::characters( const rtl::OUString
& aChars
)
178 throw (sax::SAXException
, uno::RuntimeException
)
180 OSL_DEBUG_ONLY( dbgUpdateLocation() );
184 m_pValueData
->content
+= aChars
;
186 #ifdef CONFIG_XMLPARSER_VALIDATE_WHITESPACE
188 OSL_ENSURE( isSkipping() || aChars
.trim().getLength() == 0, "Unexpected text content in configuration XML");
191 // -----------------------------------------------------------------------------
193 void SAL_CALL
BasicParser::ignorableWhitespace( const rtl::OUString
& aWhitespaces
)
194 throw (sax::SAXException
, uno::RuntimeException
)
196 OSL_DEBUG_ONLY( dbgUpdateLocation() );
199 OSL_ENSURE(false, "Configuration XML: Unexpected ignorable (!) whitespace instruction in value data");
200 if (!m_pValueData
->isNull())
201 m_pValueData
->content
+= aWhitespaces
;
203 #ifdef CONFIG_XMLPARSER_VALIDATE_WHITESPACE
205 OSL_ENSURE( aChars
.trim().getLength() == 0, "Unexpected non-space content in ignorable whitespace");
208 // -----------------------------------------------------------------------------
210 void SAL_CALL
BasicParser::processingInstruction( const rtl::OUString
& /*aTarget*/, const rtl::OUString
& /*aData*/ )
211 throw (sax::SAXException
, uno::RuntimeException
)
213 OSL_DEBUG_ONLY( dbgUpdateLocation() );
214 OSL_ENSURE(false, "Unexpected processing instruction in Configuration XML");
216 // -----------------------------------------------------------------------------
218 void SAL_CALL
BasicParser::setDocumentLocator( const uno::Reference
< sax::XLocator
>& xLocator
)
219 throw (sax::SAXException
, uno::RuntimeException
)
221 m_xLocator
= xLocator
;
222 OSL_DEBUG_ONLY( dbgUpdateLocation() );
224 // -----------------------------------------------------------------------------
226 void BasicParser::startNode( ElementInfo
const & aInfo
, const uno::Reference
< sax::XAttributeList
>& /*xAttribs*/ )
229 OSL_DEBUG_ONLY( dbgUpdateLocation() );
231 OSL_ENSURE( !isSkipping(), "While skipping, call startSkipping() instead of startNode()");
232 OSL_ENSURE( aInfo
.type
!= ElementType::property
, "For properties, call startProperty() instead of startNode()");
235 raiseParseException( "Configuration XML Parser - Invalid Data: Cannot have a node nested in a property" );
237 m_aNodes
.push(aInfo
);
238 m_bEmpty
= (aInfo
.flags
!= 0) || (aInfo
.op
> Operation::modify
);
240 OSL_POSTCOND( isInNode(), "Could not start a node ");
242 // -----------------------------------------------------------------------------
244 void BasicParser::endNode( )
246 OSL_DEBUG_ONLY( dbgUpdateLocation() );
248 OSL_ENSURE( !isSkipping(), "While skipping, honor wasSkipping() instead of calling endNode()");
249 OSL_ENSURE( !isInProperty(), "For properties, call endProperty() instead of endNode()" );
256 // -----------------------------------------------------------------------------
258 void BasicParser::ensureInNode( )
261 raiseParseException("Unexpected endElement without matching startElement");
263 // -----------------------------------------------------------------------------
265 bool BasicParser::isInNode( )
267 return ! m_aNodes
.empty();
269 // -----------------------------------------------------------------------------
271 bool BasicParser::isEmptyNode( )
275 // -----------------------------------------------------------------------------
277 ElementInfo
const & BasicParser::getActiveNodeInfo( )
281 return m_aNodes
.top();
283 // -----------------------------------------------------------------------------
285 void BasicParser::startProperty( ElementInfo
const & aInfo
, const uno::Reference
< sax::XAttributeList
>& xAttribs
)
287 OSL_DEBUG_ONLY( dbgUpdateLocation() );
289 OSL_ENSURE( !isSkipping(), "While skipping, call startSkipping() instead of startProperty()");
290 OSL_ENSURE( aInfo
.type
== ElementType::property
, "For non-property nodes, call startNode() instead of startProperty()");
293 raiseParseException( "Configuration XML Parser - Invalid Data: Properties may not nest" );
297 m_aValueType
= getDataParser().getPropertyValueType(xAttribs
);
299 catch (ElementParser::BadValueType
& error
)
301 raiseParseException(error
.message());
304 m_bInProperty
= true;
306 m_aNodes
.push(aInfo
);
309 OSL_POSTCOND( isInProperty(), "Could not get data to start a property" );
310 OSL_POSTCOND( isInUnhandledProperty(), "Could not mark property as unhandled");
312 // -----------------------------------------------------------------------------
314 void BasicParser::endProperty( )
316 OSL_DEBUG_ONLY( dbgUpdateLocation() );
318 OSL_ENSURE( !isSkipping(), "While skipping, honor wasSkipping() instead of calling endProperty()");
319 OSL_ENSURE( isInProperty(), "For non-property nodes, call endNode() instead of endProperty()" );
326 m_aValueType
= uno::Type();
327 m_bInProperty
= false;
329 OSL_POSTCOND( !isInProperty(), "Could not get mark end of property" );
331 // -----------------------------------------------------------------------------
333 uno::Type
BasicParser::getActivePropertyType()
337 // -----------------------------------------------------------------------------
339 bool BasicParser::isInProperty()
341 return m_bInProperty
;
343 // -----------------------------------------------------------------------------
345 bool BasicParser::isInUnhandledProperty()
347 return m_bEmpty
&& m_bInProperty
;
349 // -----------------------------------------------------------------------------
351 void BasicParser::startValueData(const uno::Reference
< sax::XAttributeList
>& xAttribs
)
353 OSL_DEBUG_ONLY( dbgUpdateLocation() );
356 raiseParseException( "Configuration XML Parser - Invalid Data: A value may occur only within a property" );
358 if (m_aValueType
.getTypeClass() == uno::TypeClass_ANY
)
359 raiseParseException( "Configuration XML Parser - Invalid Data: Cannot have values for properties of type 'Any'" );
362 raiseParseException( "Configuration XML Parser - Invalid Data: Unexpected element while parsing value data" );
364 m_pValueData
= new ValueData(m_aValueType
, m_xTypeConverter
);
366 m_pValueData
->setIsNull( getDataParser().isNull(xAttribs
) );
368 m_pValueData
->setSeparator( getDataParser().getSeparator(xAttribs
) );
370 OSL_ENSURE( !m_pValueData
->hasSeparator() ||
371 !m_pValueData
->isTypeSet() ||
372 m_pValueData
->isList(),
373 "Warning: Spurious oor:separator on value that is not a list");
374 OSL_ENSURE( !m_pValueData
->hasSeparator() ||
375 !m_pValueData
->isNull(),
376 "Warning: Spurious oor:separator on value that is not a list");
378 rtl::OUString aLocale
;
379 if ( getDataParser().getLanguage(xAttribs
,aLocale
) )
380 m_pValueData
->setLocalized( aLocale
);
382 // -----------------------------------------------------------------------------
384 bool BasicParser::isInValueData()
386 return m_pValueData
!= NULL
;
388 // -----------------------------------------------------------------------------
390 bool BasicParser::isValueDataLocalized()
392 OSL_ENSURE(isInValueData(), "There is no value data that could be localized");
394 return m_pValueData
&& m_pValueData
->isLocalized
;
396 // -----------------------------------------------------------------------------
398 rtl::OUString
BasicParser::getValueDataLocale()
400 OSL_ENSURE(isValueDataLocalized(), "There is no value data or it is not localized");
402 return m_pValueData
->locale
;
404 // -----------------------------------------------------------------------------
406 uno::Any
BasicParser::getCurrentValue()
408 OSL_DEBUG_ONLY( dbgUpdateLocation() );
410 OSL_ASSERT( isInValueData() );
414 if (m_pValueData
->isTypeSet())
417 aResult
= m_pValueData
->convertToAny();
419 catch (script::CannotConvertException
& e
)
421 this->raiseParseException(uno::makeAny(e
),"Configuration XML Parser - Invalid Data: Cannot convert value to type of property" );
423 else if (m_pValueData
->isNull())
427 else if (m_pValueData
->hasSeparator() || m_pValueData
->isList())
429 aResult
<<= m_pValueData
->toStringList();
433 aResult
<<= m_pValueData
->toString();
437 // -----------------------------------------------------------------------------
439 /// end collecting data for a value
440 void BasicParser::endValueData()
442 OSL_DEBUG_ONLY( dbgUpdateLocation() );
444 OSL_ASSERT( isInValueData() );
446 delete m_pValueData
, m_pValueData
= NULL
;
449 OSL_POSTCOND( !isInValueData(), "Could not end value data tag" );
450 OSL_POSTCOND( !isInUnhandledProperty(), "Could not mark property as handled" );
452 // -----------------------------------------------------------------------------
454 void BasicParser::startSkipping( const rtl::OUString
& aName
, const uno::Reference
< sax::XAttributeList
>& /*xAttribs*/ )
456 OSL_DEBUG_ONLY( dbgUpdateLocation() );
458 m_aNodes
.push( ElementInfo(aName
) );
461 // -----------------------------------------------------------------------------
463 bool BasicParser::wasSkipping( const rtl::OUString
& aName
)
465 OSL_DEBUG_ONLY( dbgUpdateLocation() );
467 if (m_nSkipLevels
== 0) return false;
469 if (m_aNodes
.empty())
470 raiseParseException( "Configuration XML Parser - Invalid XML: Unexpected end of element (while skipping data)" );
472 if (aName
!= m_aNodes
.top().name
)
473 raiseParseException( "Configuration XML Parser - Invalid XML: End tag does not match start tag (while skipping data)" );
480 // -----------------------------------------------------------------------------
482 bool BasicParser::isSkipping( )
484 return m_nSkipLevels
!= 0;
486 // -----------------------------------------------------------------------------
488 void BasicParser::raiseParseException( uno::Any
const & _aTargetException
, sal_Char
const * _pMsg
)
489 SAL_THROW((sax::SAXException
, uno::RuntimeException
))
491 OSL_DEBUG_ONLY( dbgUpdateLocation() );
493 if (_pMsg
== 0) _pMsg
= "Configuration XML Parser: Invalid Data: ";
495 rtl::OUString sMessage
= rtl::OUString::createFromAscii(_pMsg
);
498 if (_aTargetException
>>= aEx
)
499 sMessage
+= aEx
.Message
;
501 getLogger().error(sMessage
,"parse","configuration::xml::BasicParser");
502 throw sax::SAXException( sMessage
, *this, _aTargetException
);
504 // -----------------------------------------------------------------------------
506 void BasicParser::raiseParseException( sal_Char
const * _pMsg
)
507 SAL_THROW((sax::SAXException
, uno::RuntimeException
))
509 OSL_DEBUG_ONLY( dbgUpdateLocation() );
511 if (_pMsg
== 0) _pMsg
= "Configuration XML Parser: Invalid XML";
513 rtl::OUString
const sMessage
= rtl::OUString::createFromAscii(_pMsg
);
515 getLogger().error(sMessage
,"parse","configuration::xml::BasicParser");
516 throw sax::SAXException( sMessage
, *this, uno::Any() );
518 // -----------------------------------------------------------------------------
520 void BasicParser::raiseParseException( rtl::OUString
const & sMessage
)
521 SAL_THROW((sax::SAXException
, uno::RuntimeException
))
523 OSL_DEBUG_ONLY( dbgUpdateLocation() );
525 if (sMessage
.getLength() == 0) raiseParseException(NULL
);
527 getLogger().error(sMessage
,"parse","configuration::xml::BasicParser");
528 throw sax::SAXException( sMessage
, *this, uno::Any() );
530 // -----------------------------------------------------------------------------
531 // -----------------------------------------------------------------------------
534 // -----------------------------------------------------------------------------