1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24
25 // MARKER(update_precomp.py): autogen include statement, do not remove
26 #include "precompiled_svx.hxx"
27 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
28 #include <com/sun/star/xml/sax/InputSource.hpp>
29 #include <com/sun/star/xml/sax/XParser.hpp>
30 #include <com/sun/star/xml/sax/SAXParseException.hpp>
31 #include <com/sun/star/io/IOException.hpp>
32 #include <cppuhelper/implbase1.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <unotools/ucbstreamhelper.hxx>
35 #include <unotools/streamwrap.hxx>
36 #include <tools/debug.hxx>
37 #include "comphelper/anytostring.hxx"
38 #include "cppuhelper/exc_hlp.hxx"
39 #include "rtl/ref.hxx"
40
41 #include <svx/msdffimp.hxx>
42
43 #include "xmlconfig.hxx"
44
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <stack>
48
49 using ::rtl::OUString;
50 using ::com::sun::star::io::XInputStream;
51 using ::com::sun::star::io::IOException;
52
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::xml::sax;
55
56 ///////////////////////////////////////////////////////////////////////
57
58 AtomConfigMap gAtomConfigMap;
59
60 ///////////////////////////////////////////////////////////////////////
61
62 class ConfigHandler : public ::cppu::WeakAggImplHelper1<XDocumentHandler>
63 {
64 public:
65 // XDocumentHandler
66 virtual void SAL_CALL startDocument(void) throw( SAXException, RuntimeException );
67 virtual void SAL_CALL endDocument(void) throw( SAXException, RuntimeException );
68 virtual void SAL_CALL startElement(const OUString& aName, const Reference< XAttributeList > & xAttribs) throw( SAXException, RuntimeException );
69 virtual void SAL_CALL endElement(const OUString& aName) throw( SAXException, RuntimeException );
70 virtual void SAL_CALL characters(const OUString& aChars) throw( SAXException, RuntimeException );
71 virtual void SAL_CALL ignorableWhitespace(const OUString& aWhitespaces) throw( SAXException, RuntimeException );
72 virtual void SAL_CALL processingInstruction(const OUString& aTarget, const OUString& aData) throw( SAXException, RuntimeException );
73 virtual void SAL_CALL setDocumentLocator(const Reference< XLocator > & xLocator) throw( SAXException, RuntimeException );
74
75 private:
76 void errorThrow( const OUString& rErrorMessage ) throw (SAXException );
77 ElementConfigType parseType( const OUString& rErrorMessage ) throw ( SAXException );
78 void addElement( ElementConfigPtr& rElementConfig ) throw ( SAXException );
79 OUString getAttribute( const Reference< XAttributeList > & xAttribs, const sal_Char* pName ) throw( SAXException );
80
81 ElementConfigPtr importAtomConfig( const Reference< XAttributeList > & xAttribs, bool bIsContainer ) throw( SAXException );
82 ElementConfigPtr importElementConfig( const Reference< XAttributeList > & xAttribs ) throw( SAXException );
83 ElementConfigPtr importSwitchConfig( const Reference< XAttributeList > & xAttribs ) throw( SAXException );
84 ElementConfigPtr importCaseConfig( const Reference< XAttributeList > & xAttribs ) throw( SAXException );
85 ElementConfigPtr importValueElementConfig( const Reference< XAttributeList > & xAttribs ) throw( SAXException );
86
87 std::stack< ElementConfigPtr > maElementStack;
88 };
89
errorThrow(const OUString & rErrorMessage)90 void ConfigHandler::errorThrow( const OUString& rErrorMessage ) throw (SAXException )
91 {
92 Reference< XInterface > aContext;
93 Any aWrappedException;
94 throw SAXException(rErrorMessage, aContext, aWrappedException);
95 }
96
parseType(const OUString & sType)97 ElementConfigType ConfigHandler::parseType( const OUString& sType ) throw (SAXException )
98 {
99 if( sType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("uint") ) )
100 {
101 return ECT_UINT;
102 }
103 else if( sType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("byte") ) )
104 {
105 return ECT_BYTE;
106 }
107 else if( sType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("unistring") ) )
108 {
109 return ECT_UNISTRING;
110 }
111 else if( sType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("float") ) )
112 {
113 return ETC_FLOAT;
114 }
115 else if( sType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("hexdump") ) )
116 {
117 }
118 else
119 {
120 OUString aMessage( RTL_CONSTASCII_USTRINGPARAM( "unknown type: " ) );
121 aMessage += sType;
122 errorThrow( aMessage );
123 }
124
125 return ECT_HEXDUMP;
126 }
127
addElement(ElementConfigPtr & rElementConfig)128 void ConfigHandler::addElement( ElementConfigPtr& rElementConfig ) throw ( SAXException )
129 {
130 ElementConfigContainer* pParent = dynamic_cast< ElementConfigContainer* >( maElementStack.top().get() );
131
132 if( !pParent )
133 errorThrow( OUString( RTL_CONSTASCII_USTRINGPARAM( "illegal parent for element" ) ) );
134
135
136 pParent->addElementConfig( rElementConfig );
137 }
138
getAttribute(const Reference<XAttributeList> & xAttribs,const sal_Char * pName)139 OUString ConfigHandler::getAttribute( const Reference< XAttributeList > & xAttribs, const sal_Char* pName ) throw( SAXException )
140 {
141 OUString aName( OUString::createFromAscii( pName ) );
142
143 const sal_Int16 nAttrCount = xAttribs.is() ? xAttribs->getLength() : 0;
144 sal_Int16 i;
145 for(i=0; i < nAttrCount; i++)
146 {
147 if( xAttribs->getNameByIndex( i ) == aName )
148 return xAttribs->getValueByIndex( i );
149 }
150
151 OUString aMessage( RTL_CONSTASCII_USTRINGPARAM( "missing required attribute: ") );
152 aMessage += aName;
153 errorThrow( aMessage );
154
155 return OUString();
156 }
157
startDocument(void)158 void SAL_CALL ConfigHandler::startDocument(void) throw( SAXException, RuntimeException )
159 {
160 }
161
endDocument(void)162 void SAL_CALL ConfigHandler::endDocument(void) throw( SAXException, RuntimeException )
163 {
164 }
165
startElement(const OUString & aName,const Reference<XAttributeList> & xAttribs)166 void SAL_CALL ConfigHandler::startElement(const OUString& aName, const Reference< XAttributeList > & xAttribs) throw( SAXException, RuntimeException )
167 {
168 ElementConfigPtr pElement;
169
170 if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "config" ) ) )
171 {
172 return;
173 }
174
175 if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "container" ) ) )
176 {
177 pElement = importAtomConfig( xAttribs, true );
178 }
179 else if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "atom" ) ) )
180 {
181 pElement = importAtomConfig( xAttribs, false );
182 }
183 else if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "element" ) ) )
184 {
185 pElement = importElementConfig( xAttribs );
186 }
187 else if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "value" ) ) )
188 {
189 pElement = importValueElementConfig( xAttribs );
190 }
191 else if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "switch" ) ) )
192 {
193 pElement = importSwitchConfig( xAttribs );
194 }
195 else if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "case" ) ) )
196 {
197 pElement = importCaseConfig( xAttribs );
198 }
199
200 if( !pElement.get() )
201 {
202 OUString aMessage( OUString( RTL_CONSTASCII_USTRINGPARAM("unknown config element: ")) );
203 aMessage += aName;
204 errorThrow( aMessage );
205 }
206
207 maElementStack.push( pElement );
208 }
209
toInt(const OUString & rText)210 sal_Int32 toInt( const OUString& rText )
211 {
212 if( rText.compareToAscii("0x",2) == 0)
213 {
214 sal_Int32 nValue = 0;
215 const sal_Unicode *p = rText;
216 p += 2;
217 sal_Int32 nLength = rText.getLength() - 2;
218 while( (nLength--) > 0 )
219 {
220 nValue <<= 4;
221 if( *p >= '0' && *p <= '9' )
222 {
223 nValue += *p - '0';
224 }
225 else if( *p >= 'a' && *p <= 'f' )
226 {
227 nValue += *p - ('a' - 10);
228 }
229 else if( *p >= 'A' && *p <= 'F' )
230 {
231 nValue += *p - ('A' - 10 );
232 }
233 p++;
234 }
235
236 return nValue;
237 }
238 else
239 {
240 return rText.toInt32();
241 }
242 }
243
importAtomConfig(const Reference<XAttributeList> & xAttribs,bool bIsContainer)244 ElementConfigPtr ConfigHandler::importAtomConfig( const Reference< XAttributeList > & xAttribs, bool bIsContainer ) throw (SAXException)
245 {
246 if( !maElementStack.empty() )
247 errorThrow( OUString( RTL_CONSTASCII_USTRINGPARAM("atom elements must be root" ) ) );
248
249 ElementConfigPtr aPtr( new AtomConfig( getAttribute(xAttribs,"name"), bIsContainer ) );
250 gAtomConfigMap[ (UINT16)toInt(getAttribute(xAttribs,"id"))] = aPtr;
251 return aPtr;
252 }
253
importElementConfig(const Reference<XAttributeList> & xAttribs)254 ElementConfigPtr ConfigHandler::importElementConfig( const Reference< XAttributeList > & xAttribs ) throw (SAXException)
255 {
256 ElementConfigType nType = parseType( getAttribute( xAttribs, "type" ) );
257 ElementConfigPtr pElementConfig( new ElementConfigContainer( getAttribute( xAttribs, "name" ), nType ) );
258 addElement( pElementConfig );
259 return pElementConfig;
260 }
261
importValueElementConfig(const Reference<XAttributeList> & xAttribs)262 ElementConfigPtr ConfigHandler::importValueElementConfig( const Reference< XAttributeList > & xAttribs ) throw (SAXException)
263 {
264 ElementConfigPtr pElementConfig( new ElementValueConfig( getAttribute( xAttribs, "name" ), getAttribute( xAttribs, "value" ) ) );
265 addElement( pElementConfig );
266 return pElementConfig;
267 }
268
importSwitchConfig(const Reference<XAttributeList> & xAttribs)269 ElementConfigPtr ConfigHandler::importSwitchConfig( const Reference< XAttributeList > & xAttribs ) throw (SAXException)
270 {
271 ElementConfigType nType = parseType( getAttribute( xAttribs, "type" ) );
272 ElementConfigPtr pElementConfig( new SwitchElementConfig( nType ) );
273 addElement( pElementConfig );
274 return pElementConfig;
275 }
276
importCaseConfig(const Reference<XAttributeList> & xAttribs)277 ElementConfigPtr ConfigHandler::importCaseConfig( const Reference< XAttributeList > & xAttribs ) throw (SAXException)
278 {
279 ElementConfigPtr pElementConfig( new CaseElementConfig( getAttribute( xAttribs, "value" ) ) );
280 addElement( pElementConfig );
281 return pElementConfig;
282 }
283
endElement(const OUString & aName)284 void SAL_CALL ConfigHandler::endElement(const OUString& aName) throw( SAXException, RuntimeException )
285 {
286 if( aName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "config" ) ) )
287 {
288 return;
289 }
290
291 maElementStack.pop();
292 }
293
characters(const OUString & aChars)294 void SAL_CALL ConfigHandler::characters(const OUString& aChars) throw( SAXException, RuntimeException )
295 {
296 }
297
ignorableWhitespace(const OUString & aWhitespaces)298 void SAL_CALL ConfigHandler::ignorableWhitespace(const OUString& aWhitespaces) throw( SAXException, RuntimeException )
299 {
300 }
301
processingInstruction(const OUString & aTarget,const OUString & aData)302 void SAL_CALL ConfigHandler::processingInstruction(const OUString& aTarget, const OUString& aData) throw( SAXException, RuntimeException )
303 {
304 }
305
setDocumentLocator(const Reference<XLocator> & xLocator)306 void SAL_CALL ConfigHandler::setDocumentLocator(const Reference< XLocator > & xLocator) throw( SAXException, RuntimeException )
307 {
308 }
309
load_config(const OUString & rPath)310 void load_config( const OUString& rPath )
311 {
312 try
313 {
314 // create stream
315 SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( rPath, STREAM_READ );
316 Reference<XInputStream> xInputStream( new utl::OInputStreamWrapper( pIStm, sal_True ) );
317
318 // prepare ParserInputSrouce
319 InputSource aParserInput;
320 aParserInput.sSystemId = rPath;
321 aParserInput.aInputStream = xInputStream;
322
323 // get parser
324 Reference< XParser > xParser(
325 comphelper::getProcessServiceFactory()->createInstance(
326 OUString::createFromAscii("com.sun.star.xml.sax.Parser") ),
327 UNO_QUERY_THROW );
328
329 // get filter
330 ConfigHandler* pConfigHandler = new ConfigHandler();
331 Reference< XDocumentHandler > xFilter( pConfigHandler );
332
333 // connect parser and filter
334 xParser->setDocumentHandler( xFilter );
335
336 // finally, parser the stream
337 xParser->parseStream( aParserInput );
338 }
339 catch( Exception& r )
340 {
341 DBG_ERROR(
342 (rtl::OString("load_config(), "
343 "exception caught: ") +
344 rtl::OUStringToOString(
345 comphelper::anyToString( cppu::getCaughtException() ),
346 RTL_TEXTENCODING_UTF8 )).getStr() );
347
348 (void)r;
349 }
350 }
351
352 ///////////////////////////////////////////////////////////////////////
353
format(SvStream & rStream,sal_Size & nLength) const354 rtl::OUString ElementConfig::format( SvStream& rStream, sal_Size& nLength ) const
355 {
356 OUString aRet;
357 if( maName.getLength() )
358 {
359 aRet += maName;
360 aRet += OUString( RTL_CONSTASCII_USTRINGPARAM( " = " ) );
361 }
362
363 switch( mnType )
364 {
365 case ECT_BYTE: aRet += dump_byte( rStream, nLength ); break;
366 case ECT_UINT: aRet += dump_uint( rStream, nLength ); break;
367 case ECT_UNISTRING: aRet += dump_unistring( rStream, nLength ); break;
368 case ETC_FLOAT: aRet += dump_float( rStream, nLength ); break;
369 case ECT_HEXDUMP:
370 default: aRet += dump_hex( rStream, nLength ); break;
371 }
372
373 return aRet;
374 }
375
dump_hex(SvStream & rStream,sal_Size & nLength)376 rtl::OUString ElementConfig::dump_hex( SvStream& rStream, sal_Size& nLength )
377 {
378 char buffer[128];
379 OUString aOut, aEmpty;
380 OUString aHex, aAscii;
381 sal_Char c;
382 int nRow = 0;
383 while( nLength && (rStream.GetError() == 0) )
384 {
385 rStream >> c;
386 nLength--;
387
388 unsigned int i = c;
389 i &= 0xff;
390 sprintf( buffer, "%02x ", i );
391 aHex += OUString::createFromAscii( buffer );
392
393 if( !isprint( c ) )
394 c = '.';
395
396 aAscii += OUString( (sal_Unicode) c );
397 nRow++;
398
399 if( (nRow == 16) || (nLength==0) )
400 {
401 while( aHex.getLength() < (16*3) )
402 aHex += OUString( RTL_CONSTASCII_USTRINGPARAM(" ") );
403 aOut += aHex;
404 aOut += aAscii;
405 aOut += OUString( RTL_CONSTASCII_USTRINGPARAM( "\n\r" ) );
406 aHex = aEmpty;
407 aAscii = aEmpty;
408 nRow = 0;
409 }
410 }
411
412 aOut += aHex;
413 aOut += aAscii;
414
415 return aOut;
416 }
417
dump_byte(SvStream & rStream,sal_Size & nLength)418 rtl::OUString ElementConfig::dump_byte( SvStream& rStream, sal_Size& nLength )
419 {
420 OUString aRet;
421 if( nLength >= sizeof(sal_Char) )
422 {
423 sal_Char c;
424 rStream >> c;
425
426 char buffer[128];
427 sprintf( buffer, "%u", (int)c );
428 aRet += OUString::createFromAscii( buffer );
429 nLength -= sizeof(sal_Char);
430 }
431
432 return aRet;
433 }
434
dump_uint(SvStream & rStream,sal_Size & nLength)435 rtl::OUString ElementConfig::dump_uint( SvStream& rStream, sal_Size& nLength )
436 {
437 OUString aRet;
438 if( nLength >= sizeof( sal_uInt32 ) )
439 {
440 sal_uInt32 c;
441 rStream >> c;
442
443 char buffer[128];
444 sprintf( buffer, "%u", c );
445 aRet += OUString::createFromAscii( buffer );
446 nLength-= sizeof( sal_uInt32 );
447 }
448
449 return aRet;
450 }
451
dump_unistring(SvStream & rStream,sal_Size & nLength)452 rtl::OUString ElementConfig::dump_unistring( SvStream& rStream, sal_Size& nLength )
453 {
454 String aString;
455 SvxMSDffManager::MSDFFReadZString( rStream, aString, nLength, sal_True );
456 nLength = 0;
457 return aString;
458 }
459
dump_float(SvStream & rStream,sal_Size & nLength)460 rtl::OUString ElementConfig::dump_float( SvStream& rStream, sal_Size& nLength )
461 {
462 OUString aRet;
463 if( nLength >= sizeof( float ) )
464 {
465 float c;
466 rStream >> c;
467
468 char buffer[128];
469 sprintf( buffer, "%g", (double)c );
470 aRet += OUString::createFromAscii( buffer );
471 nLength-= sizeof( float );
472 }
473
474 return aRet;
475 }
476
477 ///////////////////////////////////////////////////////////////////////
478
format(SvStream & rStream,sal_Size & nLength) const479 rtl::OUString ElementConfigContainer::format( SvStream& rStream, sal_Size& nLength ) const
480 {
481 OUString aRet;
482
483 if( getType() == ETC_CONTAINER )
484 {
485
486 ElementConfigList::const_iterator aIter( maElementConfigList.begin() );
487 const ElementConfigList::const_iterator aEnd( maElementConfigList.end() );
488 while( (aIter != aEnd) && (nLength > 0) )
489 {
490 aRet += (*aIter++)->format( rStream, nLength );
491 if( (aIter != aEnd) || (nLength != 0) )
492 aRet += OUString( RTL_CONSTASCII_USTRINGPARAM( "\n\r" ) );
493 }
494
495 if( nLength )
496 aRet += ElementConfig::dump_hex( rStream, nLength );
497 }
498 else
499 {
500 aRet = getName();
501 if( aRet.getLength() )
502 aRet += OUString( RTL_CONSTASCII_USTRINGPARAM( " = " ) );
503
504 OUString aValue;
505 switch( getType() )
506 {
507 case ECT_BYTE: aValue = dump_byte( rStream, nLength ); break;
508 case ECT_UINT: aValue = dump_uint( rStream, nLength ); break;
509 case ECT_UNISTRING: aValue = dump_unistring( rStream, nLength ); break;
510 case ETC_FLOAT: aValue = dump_float( rStream, nLength ); break;
511 case ECT_HEXDUMP:
512 default: aValue = dump_hex( rStream, nLength ); break;
513 }
514
515 if( aValue.getLength() )
516 {
517 if( !maElementConfigList.empty() )
518 {
519 ElementConfigList::const_iterator aIter( maElementConfigList.begin() );
520 const ElementConfigList::const_iterator aEnd( maElementConfigList.end() );
521 while( (aIter != aEnd) && (nLength > 0) )
522 {
523 ElementValueConfig* pValue = dynamic_cast< ElementValueConfig* >( (*aIter++).get() );
524 if( pValue && pValue->getValue() == aValue )
525 {
526 aValue = pValue->getName();
527 break;
528 }
529 }
530 }
531 }
532 else
533 {
534 aValue = OUString( RTL_CONSTASCII_USTRINGPARAM("<empty!?>") );
535 }
536
537 aRet += aValue;
538 }
539
540 return aRet;
541 }
542
543 ///////////////////////////////////////////////////////////////////////
544
format(SvStream & rStream,sal_Size & nLength) const545 rtl::OUString SwitchElementConfig::format( SvStream& rStream, sal_Size& nLength ) const
546 {
547 OUString aValue;
548
549 switch( getType() )
550 {
551 case ECT_BYTE: aValue = dump_byte( rStream, nLength ); break;
552 case ECT_UINT: aValue = dump_uint( rStream, nLength ); break;
553 case ETC_FLOAT: aValue = dump_float( rStream, nLength ); break;
554 case ECT_UNISTRING: aValue = dump_unistring( rStream, nLength ); break;
555 }
556
557 if( aValue.getLength() )
558 {
559 ElementConfigList::const_iterator aIter( maElementConfigList.begin() );
560 const ElementConfigList::const_iterator aEnd( maElementConfigList.end() );
561 while( (aIter != aEnd) && (nLength > 0) )
562 {
563 CaseElementConfig* pCase = dynamic_cast< CaseElementConfig* >( (*aIter++).get() );
564 if( pCase && pCase->getValue() == aValue )
565 return pCase->format( rStream, nLength );
566 }
567 }
568
569 return ElementConfig::dump_hex( rStream, nLength );
570 }
571
572