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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include "propertyimport.hxx"
31 #include <xmloff/xmlimp.hxx>
32 #include <xmloff/xmluconv.hxx>
33 #include <xmloff/nmspmap.hxx>
34 #include <osl/diagnose.h>
35 #include <comphelper/extract.hxx>
36 #include "callbacks.hxx"
37 #include "xmloff/xmlnmspe.hxx"
38 #include <tools/date.hxx>
39 #include <tools/time.hxx>
40 #include <tools/datetime.hxx>
41 #include <com/sun/star/util/Date.hpp>
42 #include <com/sun/star/util/Time.hpp>
43 #include <com/sun/star/util/DateTime.hpp>
44 #include <unotools/datetime.hxx>
45 #include <rtl/logfile.hxx>
46 
47 #if OSL_DEBUG_LEVEL > 0
48     #ifndef _OSL_THREAD_H_
49     #include <osl/thread.h>
50     #endif
51 #endif
52 
53 //.........................................................................
54 namespace xmloff
55 {
56 //.........................................................................
57 
58 	using namespace ::com::sun::star::uno;
59 	using namespace ::com::sun::star::beans;
60 	using namespace ::com::sun::star::xml;
61 
62 	// NO using namespace ...util !!!
63 	// need a tools Date/Time/DateTime below, which would conflict with the uno types then
64 
65 #define TYPE_DATE		1
66 #define TYPE_TIME		2
67 #define TYPE_DATETIME	3
68 
69 //=====================================================================
70 //= PropertyConversion
71 //=====================================================================
72 namespace
73 {
74     //---------------------------------------------------------------------
75     ::com::sun::star::util::Time lcl_getTime(double _nValue)
76     {
77 	    ::com::sun::star::util::Time aTime;
78 	    sal_uInt32 nIntValue = sal_Int32(_nValue * 8640000);
79 	    nIntValue *= 8640000;
80 	    aTime.HundredthSeconds = (sal_uInt16)( nIntValue % 100 );
81 	    nIntValue /= 100;
82 	    aTime.Seconds = (sal_uInt16)( nIntValue % 60 );
83 	    nIntValue /= 60;
84 	    aTime.Minutes = (sal_uInt16)( nIntValue % 60 );
85 	    nIntValue /= 60;
86 	    OSL_ENSURE(nIntValue < 24, "lcl_getTime: more than a day?");
87 	    aTime.Hours = static_cast< sal_uInt16 >( nIntValue );
88 
89 	    return aTime;
90     }
91 
92     //---------------------------------------------------------------------
93     static ::com::sun::star::util::Date lcl_getDate( double _nValue )
94     {
95 	    Date aToolsDate((sal_uInt32)_nValue);
96 	    ::com::sun::star::util::Date aDate;
97 	    ::utl::typeConvert(aToolsDate, aDate);
98 	    return aDate;
99     }
100 }
101 
102 //---------------------------------------------------------------------
103 Any PropertyConversion::convertString( SvXMLImport& _rImporter, const ::com::sun::star::uno::Type& _rExpectedType,
104 	const ::rtl::OUString& _rReadCharacters, const SvXMLEnumMapEntry* _pEnumMap, const sal_Bool _bInvertBoolean )
105 {
106 	Any aReturn;
107 	sal_Bool bEnumAsInt = sal_False;
108 	switch (_rExpectedType.getTypeClass())
109 	{
110 		case TypeClass_BOOLEAN:		// sal_Bool
111 		{
112 			sal_Bool bValue;
113         #if OSL_DEBUG_LEVEL > 0
114 			sal_Bool bSuccess =
115 		#endif
116 			_rImporter.GetMM100UnitConverter().convertBool(bValue, _rReadCharacters);
117 			OSL_ENSURE(bSuccess,
118 					::rtl::OString("PropertyConversion::convertString: could not convert \"")
119 				+=	::rtl::OString(_rReadCharacters.getStr(), _rReadCharacters.getLength(), RTL_TEXTENCODING_ASCII_US)
120 				+=	::rtl::OString("\" into a boolean!"));
121 			aReturn = ::cppu::bool2any(_bInvertBoolean ? !bValue : bValue);
122 		}
123 		break;
124 		case TypeClass_SHORT:		// sal_Int16
125 		case TypeClass_LONG:		// sal_Int32
126 			if (!_pEnumMap)
127 			{	// it's a real int32/16 property
128 				sal_Int32 nValue(0);
129         #if OSL_DEBUG_LEVEL > 0
130 				sal_Bool bSuccess =
131 		#endif
132 				_rImporter.GetMM100UnitConverter().convertNumber(nValue, _rReadCharacters);
133 				OSL_ENSURE(bSuccess,
134 						::rtl::OString("PropertyConversion::convertString: could not convert \"")
135 					+=	::rtl::OString(_rReadCharacters.getStr(), _rReadCharacters.getLength(), RTL_TEXTENCODING_ASCII_US)
136 					+=	::rtl::OString("\" into an integer!"));
137 				if (TypeClass_SHORT == _rExpectedType.getTypeClass())
138 					aReturn <<= (sal_Int16)nValue;
139 				else
140 					aReturn <<= (sal_Int32)nValue;
141 				break;
142 			}
143 			bEnumAsInt = sal_True;
144 			// NO BREAK! handle it as enum
145 		case TypeClass_ENUM:
146 		{
147 			sal_uInt16 nEnumValue(0);
148         #if OSL_DEBUG_LEVEL > 0
149 			sal_Bool bSuccess =
150 		#endif
151 			_rImporter.GetMM100UnitConverter().convertEnum(nEnumValue, _rReadCharacters, _pEnumMap);
152 			OSL_ENSURE(bSuccess, "PropertyConversion::convertString: could not convert to an enum value!");
153 			if (bEnumAsInt)
154 				if (TypeClass_SHORT == _rExpectedType.getTypeClass())
155 					aReturn <<= (sal_Int16)nEnumValue;
156 				else
157 					aReturn <<= (sal_Int32)nEnumValue;
158 			else
159 				aReturn = ::cppu::int2enum((sal_Int32)nEnumValue, _rExpectedType);
160 		}
161 		break;
162 		case TypeClass_HYPER:
163 		{
164 			OSL_ENSURE(sal_False, "PropertyConversion::convertString: 64-bit integers not implemented yet!");
165 		}
166 		break;
167 		case TypeClass_DOUBLE:
168 		{
169 			double nValue;
170         #if OSL_DEBUG_LEVEL > 0
171 			sal_Bool bSuccess =
172 		#endif
173 			_rImporter.GetMM100UnitConverter().convertDouble(nValue, _rReadCharacters);
174 			OSL_ENSURE(bSuccess,
175 					::rtl::OString("PropertyConversion::convertString: could not convert \"")
176 				+=	::rtl::OString(_rReadCharacters.getStr(), _rReadCharacters.getLength(), RTL_TEXTENCODING_ASCII_US)
177 				+=	::rtl::OString("\" into a double!"));
178 			aReturn <<= (double)nValue;
179 		}
180 		break;
181 		case TypeClass_STRING:
182 			aReturn <<= _rReadCharacters;
183 			break;
184 		case TypeClass_STRUCT:
185 		{
186 			sal_Int32 nType = 0;
187             if ( _rExpectedType.equals( ::cppu::UnoType< ::com::sun::star::util::Date >::get() ) )
188                 nType = TYPE_DATE;
189             else if ( _rExpectedType.equals( ::cppu::UnoType< ::com::sun::star::util::Time >::get() ) )
190                 nType = TYPE_TIME;
191             else  if ( _rExpectedType.equals( ::cppu::UnoType< ::com::sun::star::util::DateTime >::get() ) )
192                 nType = TYPE_DATETIME;
193 
194             if ( nType )
195 			{
196 				// first extract the double
197 				double nValue = 0;
198             #if OSL_DEBUG_LEVEL > 0
199 				sal_Bool bSuccess =
200 			#endif
201 				_rImporter.GetMM100UnitConverter().convertDouble(nValue, _rReadCharacters);
202 				OSL_ENSURE(bSuccess,
203 						::rtl::OString("PropertyConversion::convertString: could not convert \"")
204 					+=	::rtl::OString(_rReadCharacters.getStr(), _rReadCharacters.getLength(), RTL_TEXTENCODING_ASCII_US)
205 					+=	::rtl::OString("\" into a double!"));
206 
207 				// then convert it into the target type
208 				switch (nType)
209 				{
210 					case TYPE_DATE:
211 					{
212 						OSL_ENSURE(((sal_uInt32)nValue) - nValue == 0,
213 							"PropertyConversion::convertString: a Date value with a fractional part?");
214 						aReturn <<= lcl_getDate(nValue);
215 					}
216 					break;
217 					case TYPE_TIME:
218 					{
219 						OSL_ENSURE(((sal_uInt32)nValue) == 0,
220 							"PropertyConversion::convertString: a Time value with more than a fractional part?");
221 						aReturn <<= lcl_getTime(nValue);
222 					}
223 					break;
224 					case TYPE_DATETIME:
225 					{
226 						::com::sun::star::util::Time aTime = lcl_getTime(nValue);
227 						::com::sun::star::util::Date aDate = lcl_getDate(nValue);
228 
229 						::com::sun::star::util::DateTime aDateTime;
230 						aDateTime.HundredthSeconds = aTime.HundredthSeconds;
231 						aDateTime.Seconds = aTime.Seconds;
232 						aDateTime.Minutes = aTime.Minutes;
233 						aDateTime.Hours = aTime.Hours;
234 						aDateTime.Day = aDate.Day;
235 						aDateTime.Month = aDate.Month;
236 						aDateTime.Year = aDate.Year;
237 						aReturn <<= aDateTime;
238 					}
239 					break;
240 				}
241 			}
242 			else
243 				OSL_ENSURE(sal_False, "PropertyConversion::convertString: unsupported property type!");
244 		}
245 		break;
246 		default:
247 			OSL_ENSURE(sal_False, "PropertyConversion::convertString: invalid type class!");
248 	}
249 
250 	return aReturn;
251 }
252 
253 //---------------------------------------------------------------------
254 Type PropertyConversion::xmlTypeToUnoType( const ::rtl::OUString& _rType )
255 {
256     Type aUnoType( ::getVoidCppuType() );
257 
258 	DECLARE_STL_USTRINGACCESS_MAP( ::com::sun::star::uno::Type, MapString2Type );
259 	static MapString2Type s_aTypeNameMap;
260 	if ( s_aTypeNameMap.empty() )
261 	{
262 		s_aTypeNameMap[ token::GetXMLToken( token::XML_BOOLEAN ) ] = ::getBooleanCppuType();
263 		s_aTypeNameMap[ token::GetXMLToken( token::XML_FLOAT )   ] = ::getCppuType( static_cast< double* >(NULL) );
264 		s_aTypeNameMap[ token::GetXMLToken( token::XML_STRING )  ] = ::getCppuType( static_cast< ::rtl::OUString* >(NULL) );
265 		s_aTypeNameMap[ token::GetXMLToken( token::XML_VOID )    ] = ::getVoidCppuType();
266 	}
267 
268 	const ConstMapString2TypeIterator aTypePos = s_aTypeNameMap.find( _rType );
269     OSL_ENSURE( s_aTypeNameMap.end() != aTypePos, "PropertyConversion::xmlTypeToUnoType: invalid property name!" );
270 	if ( s_aTypeNameMap.end() != aTypePos )
271 		aUnoType = aTypePos->second;
272 
273     return aUnoType;
274 }
275 
276 //=====================================================================
277 //= OPropertyImport
278 //=====================================================================
279 //---------------------------------------------------------------------
280 OPropertyImport::OPropertyImport(OFormLayerXMLImport_Impl& _rImport, sal_uInt16 _nPrefix, const ::rtl::OUString& _rName)
281 	:SvXMLImportContext(_rImport.getGlobalContext(), _nPrefix, _rName)
282 	,m_rContext(_rImport)
283 	,m_bTrackAttributes(sal_False)
284 {
285 }
286 
287 //---------------------------------------------------------------------
288 SvXMLImportContext* OPropertyImport::CreateChildContext(sal_uInt16 _nPrefix, const ::rtl::OUString& _rLocalName,
289 	const Reference< sax::XAttributeList >& _rxAttrList)
290 {
291 	if( token::IsXMLToken( _rLocalName, token::XML_PROPERTIES) )
292 	{
293 		return new OPropertyElementsContext( m_rContext.getGlobalContext(),
294 											 _nPrefix, _rLocalName, this);
295 	}
296 	else
297 	{
298 		OSL_ENSURE(sal_False,
299 				::rtl::OString("OPropertyImport::CreateChildContext: unknown sub element (only \"properties\" is recognized, but it is ")
300 			+=	::rtl::OString(_rLocalName.getStr(), _rLocalName.getLength(), RTL_TEXTENCODING_ASCII_US)
301 			+=	::rtl::OString(")!"));
302 		return SvXMLImportContext::CreateChildContext(_nPrefix, _rLocalName, _rxAttrList);
303 	}
304 }
305 
306 //---------------------------------------------------------------------
307 void OPropertyImport::StartElement(const Reference< sax::XAttributeList >& _rxAttrList)
308 {
309 	OSL_ENSURE(_rxAttrList.is(), "OPropertyImport::StartElement: invalid attribute list!");
310 	const sal_Int32 nAttributeCount = _rxAttrList->getLength();
311 
312 	// assume the 'worst' case: all attributes describe properties. This should save our property array
313 	// some reallocs
314 	m_aValues.reserve(nAttributeCount);
315 
316     const SvXMLNamespaceMap& rMap = m_rContext.getGlobalContext().GetNamespaceMap();
317 	sal_uInt16 nNamespace;
318 	::rtl::OUString sLocalName;
319 	for (sal_Int16 i=0; i<nAttributeCount; ++i)
320 	{
321 		nNamespace = rMap.GetKeyByAttrName(_rxAttrList->getNameByIndex(i), &sLocalName);
322 		handleAttribute(nNamespace, sLocalName, _rxAttrList->getValueByIndex(i));
323 
324 		if (m_bTrackAttributes)
325 			m_aEncounteredAttributes.insert(sLocalName);
326 	}
327 
328 	// TODO: create PropertyValues for all the attributes which were not present, because they were implied
329     // this is necessary as soon as we have properties where the XML default is different from the property
330     // default
331 }
332 
333 //---------------------------------------------------------------------
334 sal_Bool OPropertyImport::encounteredAttribute(const ::rtl::OUString& _rAttributeName) const
335 {
336 	OSL_ENSURE(m_bTrackAttributes, "OPropertyImport::encounteredAttribute: attribute tracking not enabled!");
337 	return m_aEncounteredAttributes.end() != m_aEncounteredAttributes.find(_rAttributeName);
338 }
339 
340 //---------------------------------------------------------------------
341 void OPropertyImport::Characters(const ::rtl::OUString&
342 #if OSL_DEBUG_LEVEL > 0
343 _rChars
344 #endif
345 )
346 {
347 	// ignore them (should be whitespaces only)
348 	OSL_ENSURE(0 == _rChars.trim().getLength(), "OPropertyImport::Characters: non-whitespace characters!");
349 }
350 
351 //---------------------------------------------------------------------
352 bool OPropertyImport::handleAttribute(sal_uInt16 /*_nNamespaceKey*/, const ::rtl::OUString& _rLocalName, const ::rtl::OUString& _rValue)
353 {
354 	const OAttribute2Property::AttributeAssignment* pProperty = m_rContext.getAttributeMap().getAttributeTranslation(_rLocalName);
355 	if (pProperty)
356 	{
357 		// create and store a new PropertyValue
358 		PropertyValue aNewValue;
359 		aNewValue.Name = pProperty->sPropertyName;
360 
361 		// convert the value string into the target type
362 		aNewValue.Value = PropertyConversion::convertString(m_rContext.getGlobalContext(), pProperty->aPropertyType, _rValue, pProperty->pEnumMap, pProperty->bInverseSemantics);
363 		implPushBackPropertyValue( aNewValue );
364         return true;
365 	}
366 	if (!token::IsXMLToken(_rLocalName, token::XML_TYPE))  // xlink:type is valid but ignored for <form:form>
367     {
368 #if OSL_DEBUG_LEVEL > 0
369         ::rtl::OString sMessage( "OPropertyImport::handleAttribute: Can't handle the following:\n" );
370         sMessage += ::rtl::OString( "  Attribute name: " );
371         sMessage += ::rtl::OString( _rLocalName.getStr(), _rLocalName.getLength(), osl_getThreadTextEncoding() );
372         sMessage += ::rtl::OString( "\n  value: " );
373         sMessage += ::rtl::OString( _rValue.getStr(), _rValue.getLength(), osl_getThreadTextEncoding() );
374         OSL_ENSURE( sal_False, sMessage.getStr() );
375 #endif
376         return false;
377     }
378     return true;
379 }
380 
381 //=====================================================================
382 //= OPropertyElementsContext
383 //=====================================================================
384 //---------------------------------------------------------------------
385 OPropertyElementsContext::OPropertyElementsContext(SvXMLImport& _rImport, sal_uInt16 _nPrefix, const ::rtl::OUString& _rName,
386 		const OPropertyImportRef& _rPropertyImporter)
387 	:SvXMLImportContext(_rImport, _nPrefix, _rName)
388 	,m_xPropertyImporter(_rPropertyImporter)
389 {
390 }
391 
392 //---------------------------------------------------------------------
393 SvXMLImportContext* OPropertyElementsContext::CreateChildContext(sal_uInt16 _nPrefix, const ::rtl::OUString& _rLocalName,
394 	const Reference< sax::XAttributeList >&)
395 {
396 	if( token::IsXMLToken( _rLocalName, token::XML_PROPERTY ) )
397 	{
398 		return new OSinglePropertyContext(GetImport(), _nPrefix, _rLocalName, m_xPropertyImporter);
399 	}
400 	else if( token::IsXMLToken( _rLocalName, token::XML_LIST_PROPERTY ) )
401 	{
402 		return new OListPropertyContext( GetImport(), _nPrefix, _rLocalName, m_xPropertyImporter );
403 	}
404 	else
405 	{
406 		OSL_ENSURE(sal_False,
407 				::rtl::OString("OPropertyElementsContext::CreateChildContext: unknown child element (\"")
408 			+=	::rtl::OString(_rLocalName.getStr(), _rLocalName.getLength(), RTL_TEXTENCODING_ASCII_US)
409 			+=	::rtl::OString("\")!"));
410 		return new SvXMLImportContext(GetImport(), _nPrefix, _rLocalName);
411 	}
412 }
413 
414 #if OSL_DEBUG_LEVEL > 0
415 	//---------------------------------------------------------------------
416 	void OPropertyElementsContext::StartElement(const Reference< sax::XAttributeList >& _rxAttrList)
417 	{
418 		OSL_ENSURE(0 == _rxAttrList->getLength(), "OPropertyElementsContext::StartElement: the form:properties element should not have attributes!");
419 		SvXMLImportContext::StartElement(_rxAttrList);
420 	}
421 
422 	//---------------------------------------------------------------------
423 	void OPropertyElementsContext::Characters(const ::rtl::OUString& _rChars)
424 	{
425 		OSL_ENSURE(0 == _rChars.trim(), "OPropertyElementsContext::Characters: non-whitespace characters detected!");
426 		SvXMLImportContext::Characters(_rChars);
427 	}
428 
429 #endif
430 
431 //=====================================================================
432 //= OSinglePropertyContext
433 //=====================================================================
434 //---------------------------------------------------------------------
435 OSinglePropertyContext::OSinglePropertyContext(SvXMLImport& _rImport, sal_uInt16 _nPrefix, const ::rtl::OUString& _rName,
436 		const OPropertyImportRef& _rPropertyImporter)
437 	:SvXMLImportContext(_rImport, _nPrefix, _rName)
438 	,m_xPropertyImporter(_rPropertyImporter)
439 {
440 }
441 
442 //---------------------------------------------------------------------
443 SvXMLImportContext* OSinglePropertyContext::CreateChildContext(sal_uInt16 _nPrefix, const ::rtl::OUString& _rLocalName,
444 		const Reference< sax::XAttributeList >&)
445 {
446 	OSL_ENSURE(sal_False,
447 			::rtl::OString("OSinglePropertyContext::CreateChildContext: unknown child element (\"")
448 		+=	::rtl::OString(_rLocalName.getStr(), _rLocalName.getLength(), RTL_TEXTENCODING_ASCII_US)
449 		+=	::rtl::OString("\")!"));
450 	return new SvXMLImportContext(GetImport(), _nPrefix, _rLocalName);
451 }
452 
453 //---------------------------------------------------------------------
454 void OSinglePropertyContext::StartElement(const Reference< sax::XAttributeList >& _rxAttrList)
455 {
456 	::com::sun::star::beans::PropertyValue aPropValue;		// the property the instance imports currently
457 	::com::sun::star::uno::Type	aPropType;			// the type of the property the instance imports currently
458 
459 	::rtl::OUString sType, sValue;
460     const SvXMLNamespaceMap& rMap = GetImport().GetNamespaceMap();
461 	const sal_Int16 nAttrCount = _rxAttrList.is() ? _rxAttrList->getLength() : 0;
462 	for( sal_Int16 i=0; i < nAttrCount; i++ )
463 	{
464 		const ::rtl::OUString& rAttrName = _rxAttrList->getNameByIndex( i );
465 		//const ::rtl::OUString& rValue = _rxAttrList->getValueByIndex( i );
466 
467 		::rtl::OUString aLocalName;
468 		sal_uInt16 nPrefix =
469 			rMap.GetKeyByAttrName( rAttrName,
470 															&aLocalName );
471 		if( XML_NAMESPACE_FORM == nPrefix )
472 		{
473 			if( token::IsXMLToken( aLocalName, token::XML_PROPERTY_NAME ) )
474 				aPropValue.Name = _rxAttrList->getValueByIndex( i );
475 
476 		}
477 		else if( XML_NAMESPACE_OFFICE == nPrefix )
478 		{
479 			if( token::IsXMLToken( aLocalName, token::XML_VALUE_TYPE ) )
480 				sType = _rxAttrList->getValueByIndex( i );
481 			else if( token::IsXMLToken( aLocalName,
482 										token::XML_VALUE ) ||
483 				   	 token::IsXMLToken( aLocalName,
484 										token::XML_BOOLEAN_VALUE ) ||
485 					 token::IsXMLToken( aLocalName,
486 										token::XML_STRING_VALUE ) )
487 				sValue = _rxAttrList->getValueByIndex( i );
488 		}
489 	}
490 
491 	// the name of the property
492 	OSL_ENSURE(aPropValue.Name.getLength(), "OSinglePropertyContext::StartElement: invalid property name!");
493 
494 	// needs to be translated into a ::com::sun::star::uno::Type
495     aPropType = PropertyConversion::xmlTypeToUnoType( sType );
496 	if( TypeClass_VOID == aPropType.getTypeClass() )
497 	{
498 		aPropValue.Value = Any();
499 	}
500 	else
501 	{
502 		aPropValue.Value =
503 			PropertyConversion::convertString(GetImport(), aPropType,
504 										   sValue);
505 	}
506 
507 	// now that we finally have our property value, add it to our parent object
508 	if( aPropValue.Name.getLength() )
509 		m_xPropertyImporter->implPushBackGenericPropertyValue(aPropValue);
510 }
511 
512 //=====================================================================
513 //= OListPropertyContext
514 //=====================================================================
515 //---------------------------------------------------------------------
516 OListPropertyContext::OListPropertyContext( SvXMLImport& _rImport, sal_uInt16 _nPrefix, const ::rtl::OUString& _rName,
517     const OPropertyImportRef& _rPropertyImporter )
518     :SvXMLImportContext( _rImport, _nPrefix, _rName )
519     ,m_xPropertyImporter( _rPropertyImporter )
520 {
521 }
522 
523 //---------------------------------------------------------------------
524 void OListPropertyContext::StartElement( const Reference< sax::XAttributeList >& _rxAttrList )
525 {
526 	sal_Int32 nAttributeCount = _rxAttrList->getLength();
527 
528 	sal_uInt16 nNamespace;
529 	::rtl::OUString sAttributeName;
530     const SvXMLNamespaceMap& rMap = GetImport().GetNamespaceMap();
531 	for ( sal_Int16 i = 0; i < nAttributeCount; ++i )
532 	{
533 		nNamespace = rMap.GetKeyByAttrName( _rxAttrList->getNameByIndex( i ), &sAttributeName );
534 		if  (   ( XML_NAMESPACE_FORM == nNamespace )
535             &&  ( token::IsXMLToken( sAttributeName, token::XML_PROPERTY_NAME ) )
536             )
537         {
538             m_sPropertyName = _rxAttrList->getValueByIndex( i );
539         }
540         else if (   ( XML_NAMESPACE_OFFICE == nNamespace )
541                 &&  ( token::IsXMLToken( sAttributeName, token::XML_VALUE_TYPE ) )
542                 )
543         {
544             m_sPropertyType = _rxAttrList->getValueByIndex( i );
545         }
546         else
547         {
548 		    OSL_ENSURE( false,
549 				    ::rtl::OString( "OListPropertyContext::StartElement: unknown child element (\"")
550 			    +=	::rtl::OString( sAttributeName.getStr(), sAttributeName.getLength(), RTL_TEXTENCODING_ASCII_US )
551 			    +=	::rtl::OString( "\")!" ) );
552         }
553 	}
554 }
555 
556 //---------------------------------------------------------------------
557 void OListPropertyContext::EndElement()
558 {
559     OSL_ENSURE( m_sPropertyName.getLength() && m_sPropertyType.getLength(),
560         "OListPropertyContext::EndElement: no property name or type!" );
561 
562     if ( !m_sPropertyName.getLength() || !m_sPropertyType.getLength() )
563         return;
564 
565     Sequence< Any > aListElements( m_aListValues.size() );
566     Any* pListElement = aListElements.getArray();
567     com::sun::star::uno::Type aType = PropertyConversion::xmlTypeToUnoType( m_sPropertyType );
568     for (   ::std::vector< ::rtl::OUString >::const_iterator values = m_aListValues.begin();
569             values != m_aListValues.end();
570             ++values, ++pListElement
571         )
572     {
573         *pListElement = PropertyConversion::convertString( GetImport(), aType, *values );
574     }
575 
576     PropertyValue aSequenceValue;
577     aSequenceValue.Name = m_sPropertyName;
578     aSequenceValue.Value <<= aListElements;
579 
580     m_xPropertyImporter->implPushBackGenericPropertyValue( aSequenceValue );
581 }
582 
583 //---------------------------------------------------------------------
584 SvXMLImportContext* OListPropertyContext::CreateChildContext( sal_uInt16 _nPrefix, const ::rtl::OUString& _rLocalName, const Reference< sax::XAttributeList >& /*_rxAttrList*/ )
585 {
586 	if ( token::IsXMLToken( _rLocalName, token::XML_LIST_VALUE ) )
587 	{
588         m_aListValues.resize( m_aListValues.size() + 1 );
589 		return new OListValueContext( GetImport(), _nPrefix, _rLocalName, *m_aListValues.rbegin() );
590 	}
591 	else
592 	{
593 		OSL_ENSURE( sal_False,
594 				::rtl::OString("OListPropertyContext::CreateChildContext: unknown child element (\"")
595 			+=	::rtl::OString(_rLocalName.getStr(), _rLocalName.getLength(), RTL_TEXTENCODING_ASCII_US)
596 			+=	::rtl::OString("\")!"));
597 		return new SvXMLImportContext( GetImport(), _nPrefix, _rLocalName );
598 	}
599 }
600 
601 //=====================================================================
602 //= OListValueContext
603 //=====================================================================
604 //---------------------------------------------------------------------
605 OListValueContext::OListValueContext( SvXMLImport& _rImport, sal_uInt16 _nPrefix, const ::rtl::OUString& _rName, ::rtl::OUString& _rListValueHolder )
606     :SvXMLImportContext( _rImport, _nPrefix, _rName )
607     ,m_rListValueHolder( _rListValueHolder )
608 {
609 }
610 
611 //---------------------------------------------------------------------
612 void OListValueContext::StartElement( const Reference< sax::XAttributeList >& _rxAttrList )
613 {
614 	const sal_Int32 nAttributeCount = _rxAttrList->getLength();
615 
616 	sal_uInt16 nNamespace;
617 	::rtl::OUString sAttributeName;
618     const SvXMLNamespaceMap& rMap = GetImport().GetNamespaceMap();
619 	for ( sal_Int16 i = 0; i < nAttributeCount; ++i )
620 	{
621 		nNamespace = rMap.GetKeyByAttrName( _rxAttrList->getNameByIndex( i ), &sAttributeName );
622         if ( XML_NAMESPACE_OFFICE == nNamespace )
623         {
624             if  (   token::IsXMLToken( sAttributeName, token::XML_VALUE )
625                ||   token::IsXMLToken( sAttributeName, token::XML_STRING_VALUE )
626                ||   token::IsXMLToken( sAttributeName, token::XML_BOOLEAN_VALUE )
627                 )
628             {
629                 m_rListValueHolder = _rxAttrList->getValueByIndex( i );
630                 continue;
631             }
632         }
633 
634 		OSL_ENSURE( false,
635 				::rtl::OString( "OListValueContext::StartElement: unknown child element (\"")
636 			+=	::rtl::OString( sAttributeName.getStr(), sAttributeName.getLength(), RTL_TEXTENCODING_ASCII_US )
637 			+=	::rtl::OString( "\")!" ) );
638 	}
639 }
640 
641 //.........................................................................
642 }	// namespace xmloff
643 //.........................................................................
644 
645