1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
22 #include <com/sun/star/xml/sax/InputSource.hpp>
23 #include <com/sun/star/xml/sax/Parser.hpp>
24 #include <com/sun/star/xml/sax/SAXParseException.hpp>
25 #include <com/sun/star/io/IOException.hpp>
26 #include <cppuhelper/implbase1.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <unotools/ucbstreamhelper.hxx>
29 #include <unotools/streamwrap.hxx>
30 #include "comphelper/anytostring.hxx"
31 #include "cppuhelper/exc_hlp.hxx"
32 #include "rtl/ref.hxx"
34 #include <svx/msdffimp.hxx>
36 #include "xmlconfig.hxx"
42 using ::com::sun::star::io::XInputStream
;
43 using ::com::sun::star::io::IOException
;
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::xml::sax
;
50 AtomConfigMap gAtomConfigMap
;
54 class ConfigHandler
: public ::cppu::WeakAggImplHelper1
<XDocumentHandler
>
58 virtual void SAL_CALL
startDocument() throw( SAXException
, RuntimeException
);
59 virtual void SAL_CALL
endDocument() throw( SAXException
, RuntimeException
);
60 virtual void SAL_CALL
startElement(const OUString
& aName
, const Reference
< XAttributeList
> & xAttribs
) throw( SAXException
, RuntimeException
);
61 virtual void SAL_CALL
endElement(const OUString
& aName
) throw( SAXException
, RuntimeException
);
62 virtual void SAL_CALL
characters(const OUString
& aChars
) throw( SAXException
, RuntimeException
);
63 virtual void SAL_CALL
ignorableWhitespace(const OUString
& aWhitespaces
) throw( SAXException
, RuntimeException
);
64 virtual void SAL_CALL
processingInstruction(const OUString
& aTarget
, const OUString
& aData
) throw( SAXException
, RuntimeException
);
65 virtual void SAL_CALL
setDocumentLocator(const Reference
< XLocator
> & xLocator
) throw( SAXException
, RuntimeException
);
68 void errorThrow( const OUString
& rErrorMessage
) throw (SAXException
);
69 ElementConfigType
parseType( const OUString
& rErrorMessage
) throw ( SAXException
);
70 void addElement( ElementConfigPtr
& rElementConfig
) throw ( SAXException
);
71 OUString
getAttribute( const Reference
< XAttributeList
> & xAttribs
, const sal_Char
* pName
) throw( SAXException
);
73 ElementConfigPtr
importAtomConfig( const Reference
< XAttributeList
> & xAttribs
, bool bIsContainer
) throw( SAXException
);
74 ElementConfigPtr
importElementConfig( const Reference
< XAttributeList
> & xAttribs
) throw( SAXException
);
75 ElementConfigPtr
importSwitchConfig( const Reference
< XAttributeList
> & xAttribs
) throw( SAXException
);
76 ElementConfigPtr
importCaseConfig( const Reference
< XAttributeList
> & xAttribs
) throw( SAXException
);
77 ElementConfigPtr
importValueElementConfig( const Reference
< XAttributeList
> & xAttribs
) throw( SAXException
);
79 std::stack
< ElementConfigPtr
> maElementStack
;
82 void ConfigHandler::errorThrow( const OUString
& rErrorMessage
) throw (SAXException
)
84 Reference
< XInterface
> aContext
;
85 Any aWrappedException
;
86 throw SAXException(rErrorMessage
, aContext
, aWrappedException
);
89 ElementConfigType
ConfigHandler::parseType( const OUString
& sType
) throw (SAXException
)
91 if ( sType
== "uint" )
95 else if ( sType
== "byte" )
99 else if ( sType
== "unistring" )
101 return ECT_UNISTRING
;
103 else if ( sType
== "float" )
107 else if ( sType
== "hexdump" )
112 OUString
aMessage( "unknown type: " );
114 errorThrow( aMessage
);
120 void ConfigHandler::addElement( ElementConfigPtr
& rElementConfig
) throw ( SAXException
)
122 ElementConfigContainer
* pParent
= dynamic_cast< ElementConfigContainer
* >( maElementStack
.top().get() );
125 errorThrow( OUString( "illegal parent for element" ) );
128 pParent
->addElementConfig( rElementConfig
);
131 OUString
ConfigHandler::getAttribute( const Reference
< XAttributeList
> & xAttribs
, const sal_Char
* pName
) throw( SAXException
)
133 OUString
aName( OUString::createFromAscii( pName
) );
135 const sal_Int16 nAttrCount
= xAttribs
.is() ? xAttribs
->getLength() : 0;
137 for(i
=0; i
< nAttrCount
; i
++)
139 if( xAttribs
->getNameByIndex( i
) == aName
)
140 return xAttribs
->getValueByIndex( i
);
143 OUString
aMessage( "missing required attribute: " );
145 errorThrow( aMessage
);
150 void SAL_CALL
ConfigHandler::startDocument() throw( SAXException
, RuntimeException
)
154 void SAL_CALL
ConfigHandler::endDocument() throw( SAXException
, RuntimeException
)
158 void SAL_CALL
ConfigHandler::startElement(const OUString
& aName
, const Reference
< XAttributeList
> & xAttribs
) throw( SAXException
, RuntimeException
)
160 ElementConfigPtr pElement
;
162 if ( aName
== "config" )
167 if ( aName
== "container" )
169 pElement
= importAtomConfig( xAttribs
, true );
171 else if ( aName
== "atom" )
173 pElement
= importAtomConfig( xAttribs
, false );
175 else if ( aName
== "element" )
177 pElement
= importElementConfig( xAttribs
);
179 else if ( aName
== "value" )
181 pElement
= importValueElementConfig( xAttribs
);
183 else if ( aName
== "switch" )
185 pElement
= importSwitchConfig( xAttribs
);
187 else if ( aName
== "case" )
189 pElement
= importCaseConfig( xAttribs
);
192 if( !pElement
.get() )
194 OUString
aMessage( "unknown config element: " );
196 errorThrow( aMessage
);
199 maElementStack
.push( pElement
);
202 sal_Int32
toInt( const OUString
& rText
)
204 if( rText
.startsWith("0x"))
206 sal_Int32 nValue
= 0;
207 const sal_Unicode
*p
= rText
;
209 sal_Int32 nLength
= rText
.getLength() - 2;
210 while( (nLength
--) > 0 )
213 if( *p
>= '0' && *p
<= '9' )
217 else if( *p
>= 'a' && *p
<= 'f' )
219 nValue
+= *p
- ('a' - 10);
221 else if( *p
>= 'A' && *p
<= 'F' )
223 nValue
+= *p
- ('A' - 10 );
232 return rText
.toInt32();
236 ElementConfigPtr
ConfigHandler::importAtomConfig( const Reference
< XAttributeList
> & xAttribs
, bool bIsContainer
) throw (SAXException
)
238 if( !maElementStack
.empty() )
239 errorThrow( OUString( "atom elements must be root" ) );
241 ElementConfigPtr
aPtr( new AtomConfig( getAttribute(xAttribs
,"name"), bIsContainer
) );
242 gAtomConfigMap
[ (UINT16
)toInt(getAttribute(xAttribs
,"id"))] = aPtr
;
246 ElementConfigPtr
ConfigHandler::importElementConfig( const Reference
< XAttributeList
> & xAttribs
) throw (SAXException
)
248 ElementConfigType nType
= parseType( getAttribute( xAttribs
, "type" ) );
249 ElementConfigPtr
pElementConfig( new ElementConfigContainer( getAttribute( xAttribs
, "name" ), nType
) );
250 addElement( pElementConfig
);
251 return pElementConfig
;
254 ElementConfigPtr
ConfigHandler::importValueElementConfig( const Reference
< XAttributeList
> & xAttribs
) throw (SAXException
)
256 ElementConfigPtr
pElementConfig( new ElementValueConfig( getAttribute( xAttribs
, "name" ), getAttribute( xAttribs
, "value" ) ) );
257 addElement( pElementConfig
);
258 return pElementConfig
;
261 ElementConfigPtr
ConfigHandler::importSwitchConfig( const Reference
< XAttributeList
> & xAttribs
) throw (SAXException
)
263 ElementConfigType nType
= parseType( getAttribute( xAttribs
, "type" ) );
264 ElementConfigPtr
pElementConfig( new SwitchElementConfig( nType
) );
265 addElement( pElementConfig
);
266 return pElementConfig
;
269 ElementConfigPtr
ConfigHandler::importCaseConfig( const Reference
< XAttributeList
> & xAttribs
) throw (SAXException
)
271 ElementConfigPtr
pElementConfig( new CaseElementConfig( getAttribute( xAttribs
, "value" ) ) );
272 addElement( pElementConfig
);
273 return pElementConfig
;
276 void SAL_CALL
ConfigHandler::endElement(const OUString
& aName
) throw( SAXException
, RuntimeException
)
278 if ( aName
== "config" )
283 maElementStack
.pop();
286 void SAL_CALL
ConfigHandler::characters(const OUString
& aChars
) throw( SAXException
, RuntimeException
)
290 void SAL_CALL
ConfigHandler::ignorableWhitespace(const OUString
& aWhitespaces
) throw( SAXException
, RuntimeException
)
294 void SAL_CALL
ConfigHandler::processingInstruction(const OUString
& aTarget
, const OUString
& aData
) throw( SAXException
, RuntimeException
)
298 void SAL_CALL
ConfigHandler::setDocumentLocator(const Reference
< XLocator
> & xLocator
) throw( SAXException
, RuntimeException
)
302 void load_config( const OUString
& rPath
)
307 SvStream
* pIStm
= ::utl::UcbStreamHelper::CreateStream( rPath
, StreamMode::READ
);
308 Reference
<XInputStream
> xInputStream( new utl::OInputStreamWrapper( pIStm
, sal_True
) );
310 // prepare ParserInputSrouce
311 InputSource aParserInput
;
312 aParserInput
.sSystemId
= rPath
;
313 aParserInput
.aInputStream
= xInputStream
;
316 Reference
< XParser
> xParser
= Parser::create(comphelper::getProcessComponentContext());
319 ConfigHandler
* pConfigHandler
= new ConfigHandler();
320 Reference
< XDocumentHandler
> xFilter( pConfigHandler
);
322 // connect parser and filter
323 xParser
->setDocumentHandler( xFilter
);
325 // finally, parser the stream
326 xParser
->parseStream( aParserInput
);
331 (OString("load_config(), "
332 "exception caught: ") +
334 comphelper::anyToString( cppu::getCaughtException() ),
335 RTL_TEXTENCODING_UTF8
)).getStr() );
341 OUString
ElementConfig::format( SvStream
& rStream
, sal_Size
& nLength
) const
344 if( maName
.getLength() )
346 aRet
+= maName
+ " = ";
351 case ECT_BYTE
: aRet
+= dump_byte( rStream
, nLength
); break;
352 case ECT_UINT
: aRet
+= dump_uint( rStream
, nLength
); break;
353 case ECT_UNISTRING
: aRet
+= dump_unistring( rStream
, nLength
); break;
354 case ETC_FLOAT
: aRet
+= dump_float( rStream
, nLength
); break;
356 default: aRet
+= dump_hex( rStream
, nLength
); break;
362 OUString
ElementConfig::dump_hex( SvStream
& rStream
, sal_Size
& nLength
)
365 OUString aOut
, aEmpty
;
366 OUString aHex
, aAscii
;
369 while( nLength
&& (rStream
.GetError() == 0) )
376 sprintf( buffer
, "%02x ", i
);
377 aHex
+= OUString::createFromAscii( buffer
);
382 aAscii
+= OUString( (sal_Unicode
) c
);
385 if( (nRow
== 16) || (nLength
==0) )
387 while( aHex
.getLength() < (16*3) )
404 OUString
ElementConfig::dump_byte( SvStream
& rStream
, sal_Size
& nLength
)
407 if( nLength
>= sizeof(sal_Char
) )
413 sprintf( buffer
, "%u", (int)c
);
414 aRet
+= OUString::createFromAscii( buffer
);
415 nLength
-= sizeof(sal_Char
);
421 OUString
ElementConfig::dump_uint( SvStream
& rStream
, sal_Size
& nLength
)
424 if( nLength
>= sizeof( sal_uInt32
) )
430 sprintf( buffer
, "%u", c
);
431 aRet
+= OUString::createFromAscii( buffer
);
432 nLength
-= sizeof( sal_uInt32
);
438 OUString
ElementConfig::dump_unistring( SvStream
& rStream
, sal_Size
& nLength
)
440 String aString
= SvxMSDffManager::MSDFFReadZString( rStream
, nLength
, sal_True
);
445 OUString
ElementConfig::dump_float( SvStream
& rStream
, sal_Size
& nLength
)
448 if( nLength
>= sizeof( float ) )
454 sprintf( buffer
, "%g", (double)c
);
455 aRet
+= OUString::createFromAscii( buffer
);
456 nLength
-= sizeof( float );
464 OUString
ElementConfigContainer::format( SvStream
& rStream
, sal_Size
& nLength
) const
468 if( getType() == ETC_CONTAINER
)
471 ElementConfigList::const_iterator
aIter( maElementConfigList
.begin() );
472 const ElementConfigList::const_iterator
aEnd( maElementConfigList
.end() );
473 while( (aIter
!= aEnd
) && (nLength
> 0) )
475 aRet
+= (*aIter
++)->format( rStream
, nLength
);
476 if( (aIter
!= aEnd
) || (nLength
!= 0) )
481 aRet
+= ElementConfig::dump_hex( rStream
, nLength
);
486 if( aRet
.getLength() )
492 case ECT_BYTE
: aValue
= dump_byte( rStream
, nLength
); break;
493 case ECT_UINT
: aValue
= dump_uint( rStream
, nLength
); break;
494 case ECT_UNISTRING
: aValue
= dump_unistring( rStream
, nLength
); break;
495 case ETC_FLOAT
: aValue
= dump_float( rStream
, nLength
); break;
497 default: aValue
= dump_hex( rStream
, nLength
); break;
500 if( aValue
.getLength() )
502 if( !maElementConfigList
.empty() )
504 ElementConfigList::const_iterator
aIter( maElementConfigList
.begin() );
505 const ElementConfigList::const_iterator
aEnd( maElementConfigList
.end() );
506 while( (aIter
!= aEnd
) && (nLength
> 0) )
508 ElementValueConfig
* pValue
= dynamic_cast< ElementValueConfig
* >( (*aIter
++).get() );
509 if( pValue
&& pValue
->getValue() == aValue
)
511 aValue
= pValue
->getName();
519 aValue
= "<empty!?>";
530 OUString
SwitchElementConfig::format( SvStream
& rStream
, sal_Size
& nLength
) const
536 case ECT_BYTE
: aValue
= dump_byte( rStream
, nLength
); break;
537 case ECT_UINT
: aValue
= dump_uint( rStream
, nLength
); break;
538 case ETC_FLOAT
: aValue
= dump_float( rStream
, nLength
); break;
539 case ECT_UNISTRING
: aValue
= dump_unistring( rStream
, nLength
); break;
542 if( aValue
.getLength() )
544 ElementConfigList::const_iterator
aIter( maElementConfigList
.begin() );
545 const ElementConfigList::const_iterator
aEnd( maElementConfigList
.end() );
546 while( (aIter
!= aEnd
) && (nLength
> 0) )
548 CaseElementConfig
* pCase
= dynamic_cast< CaseElementConfig
* >( (*aIter
++).get() );
549 if( pCase
&& pCase
->getValue() == aValue
)
550 return pCase
->format( rStream
, nLength
);
554 return ElementConfig::dump_hex( rStream
, nLength
);
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */