office-gobmx/configmgr/source/xml/basicparser.cxx
Rüdiger Timm db1b70654a INTEGRATION: CWS changefileheader (1.10.72); FILE MERGED
2008/04/01 12:27:39 thb 1.10.72.2: #i85898# Stripping all external header guards
2008/03/31 12:23:00 rt 1.10.72.1: #i87441# Change license header to LPGL v3.
2008-04-11 13:00:32 +00:00

538 lines
17 KiB
C++

/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: basicparser.cxx,v $
* $Revision: 1.11 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_configmgr.hxx"
#include "basicparser.hxx"
#include <com/sun/star/xml/sax/SAXException.hpp>
#include "valuetypeconverter.hxx"
// -----------------------------------------------------------------------------
namespace configmgr
{
// -----------------------------------------------------------------------------
namespace xml
{
// -----------------------------------------------------------------------------
namespace uno = ::com::sun::star::uno;
namespace sax = ::com::sun::star::xml::sax;
// -----------------------------------------------------------------------------
namespace
{
typedef uno::Reference< script::XTypeConverter > TypeConverter;
static inline
TypeConverter createTCV(BasicParser::Context const & _xContext)
{
OSL_ENSURE(_xContext.is(),"Cannot create Parser without a Context");
static const rtl::OUString k_sTCVService(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.script.Converter"));
uno::Reference< lang::XMultiComponentFactory > xSvcFactory = _xContext->getServiceManager();
return TypeConverter::query(xSvcFactory->createInstanceWithContext(k_sTCVService,_xContext));
}
}
// -----------------------------------------------------------------------------
struct BasicParser::ValueData : ValueConverter
{
OUString content;
OUString locale;
bool isLocalized;
ValueData(uno::Type const& _aType, TypeConverter const & _xTCV)
: ValueConverter(_aType, _xTCV)
, content()
, locale()
, isLocalized(false)
{
}
uno::Any convertToAny() const
{
return ValueConverter::convertToAny(this->content);
}
OUString toString() const
{
return this->content;
}
uno::Sequence<OUString> toStringList() const
{
return ValueConverter::splitStringList(this->content);
}
void setLocalized(OUString const & _aLocale)
{
isLocalized = true;
locale = _aLocale;
}
};
// -----------------------------------------------------------------------------
BasicParser::BasicParser(Context const & _xContext)
: m_xTypeConverter( createTCV(_xContext) )
, m_xLocator(NULL)
, m_aDataParser(Logger(_xContext))
, m_aNodes()
, m_aValueType()
, m_pValueData(NULL)
, m_nSkipLevels(0)
, m_bEmpty(true)
, m_bInProperty(false)
{
if (!m_xTypeConverter.is())
throw uno::RuntimeException();
OSL_DEBUG_ONLY( dbgUpdateLocation() );
}
// -----------------------------------------------------------------------------
BasicParser::~BasicParser()
{
delete m_pValueData;
}
// -----------------------------------------------------------------------------
#if OSL_DEBUG_LEVEL > 0
void BasicParser::dbgUpdateLocation()
{
#ifndef DBG_UTIL
OUString dbgPublicId, dbgSystemId;
sal_Int32 dbgLineNo, dbgColumnNo;
#endif // OSL_DEBUG_LEVEL
if (m_xLocator.is())
{
dbgPublicId = m_xLocator->getPublicId();
dbgSystemId = m_xLocator->getSystemId();
dbgLineNo = m_xLocator->getLineNumber();
dbgColumnNo = m_xLocator->getColumnNumber();
}
else
{
dbgPublicId = dbgSystemId = OUString::createFromAscii("<<<unknown>>>");
dbgLineNo = dbgColumnNo = -1;
}
}
#endif
// -----------------------------------------------------------------------------
void SAL_CALL BasicParser::startDocument( )
throw (sax::SAXException, uno::RuntimeException)
{
m_aDataParser.reset();
m_aValueType = uno::Type();
m_bInProperty = false;
m_nSkipLevels = 0;
delete m_pValueData, m_pValueData = NULL;
while (!m_aNodes.empty()) m_aNodes.pop();
m_bEmpty = true;
OSL_DEBUG_ONLY( dbgUpdateLocation() );
}
// -----------------------------------------------------------------------------
void SAL_CALL BasicParser::endDocument( ) throw (sax::SAXException, uno::RuntimeException)
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
if (!m_aNodes.empty() || isSkipping() || isInValueData())
raiseParseException( "Configuration XML Parser - Invalid XML: Unexpected end of document" );
m_xLocator.clear();
}
// -----------------------------------------------------------------------------
void SAL_CALL BasicParser::characters( const OUString& aChars )
throw (sax::SAXException, uno::RuntimeException)
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
if (isInValueData())
{
m_pValueData->content += aChars;
}
#ifdef CONFIG_XMLPARSER_VALIDATE_WHITESPACE
else
OSL_ENSURE( isSkipping() || aChars.trim().getLength() == 0, "Unexpected text content in configuration XML");
#endif
}
// -----------------------------------------------------------------------------
void SAL_CALL BasicParser::ignorableWhitespace( const OUString& aWhitespaces )
throw (sax::SAXException, uno::RuntimeException)
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
if (isInValueData())
{
OSL_ENSURE(false, "Configuration XML: Unexpected ignorable (!) whitespace instruction in value data");
if (!m_pValueData->isNull())
m_pValueData->content += aWhitespaces;
}
#ifdef CONFIG_XMLPARSER_VALIDATE_WHITESPACE
else
OSL_ENSURE( aChars.trim().getLength() == 0, "Unexpected non-space content in ignorable whitespace");
#endif
}
// -----------------------------------------------------------------------------
void SAL_CALL BasicParser::processingInstruction( const OUString& /*aTarget*/, const OUString& /*aData*/ )
throw (sax::SAXException, uno::RuntimeException)
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
OSL_ENSURE(false, "Unexpected processing instruction in Configuration XML");
}
// -----------------------------------------------------------------------------
void SAL_CALL BasicParser::setDocumentLocator( const uno::Reference< sax::XLocator >& xLocator )
throw (sax::SAXException, uno::RuntimeException)
{
m_xLocator = xLocator;
OSL_DEBUG_ONLY( dbgUpdateLocation() );
}
// -----------------------------------------------------------------------------
void BasicParser::startNode( ElementInfo const & aInfo, const uno::Reference< sax::XAttributeList >& /*xAttribs*/ )
{
{ (void)aInfo; }
OSL_DEBUG_ONLY( dbgUpdateLocation() );
OSL_ENSURE( !isSkipping(), "While skipping, call startSkipping() instead of startNode()");
OSL_ENSURE( aInfo.type != ElementType::property, "For properties, call startProperty() instead of startNode()");
if (isInProperty())
raiseParseException( "Configuration XML Parser - Invalid Data: Cannot have a node nested in a property" );
m_aNodes.push(aInfo);
m_bEmpty = (aInfo.flags != 0) || (aInfo.op > Operation::modify);
OSL_POSTCOND( isInNode(), "Could not start a node ");
}
// -----------------------------------------------------------------------------
void BasicParser::endNode( )
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
OSL_ENSURE( !isSkipping(), "While skipping, honor wasSkipping() instead of calling endNode()");
OSL_ENSURE( !isInProperty(), "For properties, call endProperty() instead of endNode()" );
ensureInNode();
m_aNodes.pop();
m_bEmpty = false;
}
// -----------------------------------------------------------------------------
void BasicParser::ensureInNode( )
{
if (!isInNode())
raiseParseException("Unexpected endElement without matching startElement");
}
// -----------------------------------------------------------------------------
bool BasicParser::isInNode( )
{
return ! m_aNodes.empty();
}
// -----------------------------------------------------------------------------
bool BasicParser::isEmptyNode( )
{
return m_bEmpty;
}
// -----------------------------------------------------------------------------
ElementInfo const & BasicParser::getActiveNodeInfo( )
{
ensureInNode();
return m_aNodes.top();
}
// -----------------------------------------------------------------------------
void BasicParser::startProperty( ElementInfo const & aInfo, const uno::Reference< sax::XAttributeList >& xAttribs )
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
OSL_ENSURE( !isSkipping(), "While skipping, call startSkipping() instead of startProperty()");
OSL_ENSURE( aInfo.type == ElementType::property, "For non-property nodes, call startNode() instead of startProperty()");
if (isInProperty())
raiseParseException( "Configuration XML Parser - Invalid Data: Properties may not nest" );
try
{
m_aValueType = getDataParser().getPropertyValueType(xAttribs);
}
catch (ElementParser::BadValueType & error)
{
raiseParseException(error.message());
}
m_bInProperty = true;
m_aNodes.push(aInfo);
m_bEmpty = true;
OSL_POSTCOND( isInProperty(), "Could not get data to start a property" );
OSL_POSTCOND( isInUnhandledProperty(), "Could not mark property as unhandled");
}
// -----------------------------------------------------------------------------
void BasicParser::endProperty( )
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
OSL_ENSURE( !isSkipping(), "While skipping, honor wasSkipping() instead of calling endProperty()");
OSL_ENSURE( isInProperty(), "For non-property nodes, call endNode() instead of endProperty()" );
ensureInNode();
m_aNodes.pop();
m_bEmpty = false;
m_aValueType = uno::Type();
m_bInProperty = false;
OSL_POSTCOND( !isInProperty(), "Could not get mark end of property" );
}
// -----------------------------------------------------------------------------
uno::Type BasicParser::getActivePropertyType()
{
return m_aValueType;
}
// -----------------------------------------------------------------------------
bool BasicParser::isInProperty()
{
return m_bInProperty;
}
// -----------------------------------------------------------------------------
bool BasicParser::isInUnhandledProperty()
{
return m_bEmpty && m_bInProperty;
}
// -----------------------------------------------------------------------------
void BasicParser::startValueData(const uno::Reference< sax::XAttributeList >& xAttribs)
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
if (!isInProperty())
raiseParseException( "Configuration XML Parser - Invalid Data: A value may occur only within a property" );
if (m_aValueType.getTypeClass() == uno::TypeClass_ANY)
raiseParseException( "Configuration XML Parser - Invalid Data: Cannot have values for properties of type 'Any'" );
if (isInValueData())
raiseParseException( "Configuration XML Parser - Invalid Data: Unexpected element while parsing value data" );
m_pValueData = new ValueData(m_aValueType, m_xTypeConverter);
m_pValueData->setIsNull( getDataParser().isNull(xAttribs) );
m_pValueData->setSeparator( getDataParser().getSeparator(xAttribs) );
OSL_ENSURE( !m_pValueData->hasSeparator() ||
!m_pValueData->isTypeSet() ||
m_pValueData->isList(),
"Warning: Spurious oor:separator on value that is not a list");
OSL_ENSURE( !m_pValueData->hasSeparator() ||
!m_pValueData->isNull(),
"Warning: Spurious oor:separator on value that is not a list");
OUString aLocale;
if ( getDataParser().getLanguage(xAttribs,aLocale) )
m_pValueData->setLocalized( aLocale );
}
// -----------------------------------------------------------------------------
bool BasicParser::isInValueData()
{
return m_pValueData != NULL;
}
// -----------------------------------------------------------------------------
bool BasicParser::isValueDataLocalized()
{
OSL_ENSURE(isInValueData(), "There is no value data that could be localized");
return m_pValueData && m_pValueData->isLocalized;
}
// -----------------------------------------------------------------------------
OUString BasicParser::getValueDataLocale()
{
OSL_ENSURE(isValueDataLocalized(), "There is no value data or it is not localized");
return m_pValueData->locale;
}
// -----------------------------------------------------------------------------
uno::Any BasicParser::getCurrentValue()
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
OSL_ASSERT( isInValueData() );
uno::Any aResult;
if (m_pValueData->isTypeSet())
try
{
aResult = m_pValueData->convertToAny();
}
catch (script::CannotConvertException & e)
{
this->raiseParseException(uno::makeAny(e),"Configuration XML Parser - Invalid Data: Cannot convert value to type of property" );
}
else if (m_pValueData->isNull())
{
// nothing to do
}
else if (m_pValueData->hasSeparator() || m_pValueData->isList())
{
aResult <<= m_pValueData->toStringList();
}
else
{
aResult <<= m_pValueData->toString();
}
return aResult;
}
// -----------------------------------------------------------------------------
/// end collecting data for a value
void BasicParser::endValueData()
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
OSL_ASSERT( isInValueData() );
delete m_pValueData, m_pValueData = NULL;
m_bEmpty = false;
OSL_POSTCOND( !isInValueData(), "Could not end value data tag" );
OSL_POSTCOND( !isInUnhandledProperty(), "Could not mark property as handled" );
}
// -----------------------------------------------------------------------------
void BasicParser::startSkipping( const OUString& aName, const uno::Reference< sax::XAttributeList >& /*xAttribs*/ )
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
m_aNodes.push( ElementInfo(aName) );
++m_nSkipLevels;
}
// -----------------------------------------------------------------------------
bool BasicParser::wasSkipping( const OUString& aName )
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
if (m_nSkipLevels == 0) return false;
if (m_aNodes.empty())
raiseParseException( "Configuration XML Parser - Invalid XML: Unexpected end of element (while skipping data)" );
if (aName != m_aNodes.top().name)
raiseParseException( "Configuration XML Parser - Invalid XML: End tag does not match start tag (while skipping data)" );
--m_nSkipLevels;
m_aNodes.pop();
return true;
}
// -----------------------------------------------------------------------------
bool BasicParser::isSkipping( )
{
return m_nSkipLevels != 0;
}
// -----------------------------------------------------------------------------
void BasicParser::raiseParseException( uno::Any const & _aTargetException, sal_Char const * _pMsg )
CFG_THROW2 (sax::SAXException, uno::RuntimeException)
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
if (_pMsg == 0) _pMsg = "Configuration XML Parser: Invalid Data: ";
OUString sMessage = OUString::createFromAscii(_pMsg);
uno::Exception aEx;
if (_aTargetException >>= aEx)
sMessage += aEx.Message;
getLogger().error(sMessage,"parse","configuration::xml::BasicParser");
throw sax::SAXException( sMessage, *this, _aTargetException );
}
// -----------------------------------------------------------------------------
void BasicParser::raiseParseException( sal_Char const * _pMsg )
CFG_THROW2 (sax::SAXException, uno::RuntimeException)
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
if (_pMsg == 0) _pMsg = "Configuration XML Parser: Invalid XML";
OUString const sMessage = OUString::createFromAscii(_pMsg);
getLogger().error(sMessage,"parse","configuration::xml::BasicParser");
throw sax::SAXException( sMessage, *this, uno::Any() );
}
// -----------------------------------------------------------------------------
void BasicParser::raiseParseException( OUString const & sMessage )
CFG_THROW2 (sax::SAXException, uno::RuntimeException)
{
OSL_DEBUG_ONLY( dbgUpdateLocation() );
if (sMessage.getLength() == 0) raiseParseException(NULL);
getLogger().error(sMessage,"parse","configuration::xml::BasicParser");
throw sax::SAXException( sMessage, *this, uno::Any() );
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
} // namespace
// -----------------------------------------------------------------------------
} // namespace