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