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 31 #include "SchemaRestrictionContext.hxx" 32 #include "xformsapi.hxx" 33 34 #include <xmloff/xmltoken.hxx> 35 #include <xmloff/nmspmap.hxx> 36 #include <xmloff/xmlnmspe.hxx> 37 #include <xmloff/xmltkmap.hxx> 38 #include <xmloff/xmluconv.hxx> 39 #include <xmloff/xmlimp.hxx> 40 41 #include <com/sun/star/beans/XPropertySet.hpp> 42 #include <com/sun/star/uno/Type.hxx> 43 #include <com/sun/star/util/Date.hpp> 44 #include <com/sun/star/util/Time.hpp> 45 #include <com/sun/star/util/DateTime.hpp> 46 #include <com/sun/star/xforms/XDataTypeRepository.hpp> 47 #include <com/sun/star/xsd/DataTypeClass.hpp> 48 #include <com/sun/star/xsd/WhiteSpaceTreatment.hpp> 49 50 #include <tools/debug.hxx> 51 52 53 using rtl::OUString; 54 using com::sun::star::uno::Reference; 55 using com::sun::star::uno::Exception; 56 using com::sun::star::uno::Any; 57 using com::sun::star::uno::makeAny; 58 using com::sun::star::uno::UNO_QUERY; 59 using com::sun::star::util::Date; 60 using com::sun::star::util::DateTime; 61 using com::sun::star::xml::sax::XAttributeList; 62 using com::sun::star::beans::XPropertySet; 63 using com::sun::star::beans::XPropertySetInfo; 64 using com::sun::star::xforms::XDataTypeRepository; 65 using namespace xmloff::token; 66 67 68 69 70 static SvXMLTokenMapEntry aAttributes[] = 71 { 72 TOKEN_MAP_ENTRY( NONE, BASE ), 73 XML_TOKEN_MAP_END 74 }; 75 76 static SvXMLTokenMapEntry aChildren[] = 77 { 78 TOKEN_MAP_ENTRY( XSD, LENGTH ), 79 TOKEN_MAP_ENTRY( XSD, MINLENGTH ), 80 TOKEN_MAP_ENTRY( XSD, MAXLENGTH ), 81 TOKEN_MAP_ENTRY( XSD, MININCLUSIVE ), 82 TOKEN_MAP_ENTRY( XSD, MINEXCLUSIVE ), 83 TOKEN_MAP_ENTRY( XSD, MAXINCLUSIVE ), 84 TOKEN_MAP_ENTRY( XSD, MAXEXCLUSIVE ), 85 TOKEN_MAP_ENTRY( XSD, PATTERN ), 86 // ??? XML_ENUMERATION 87 TOKEN_MAP_ENTRY( XSD, WHITESPACE ), 88 TOKEN_MAP_ENTRY( XSD, TOTALDIGITS ), 89 TOKEN_MAP_ENTRY( XSD, FRACTIONDIGITS ), 90 XML_TOKEN_MAP_END 91 }; 92 93 94 SchemaRestrictionContext::SchemaRestrictionContext( 95 SvXMLImport& rImport, 96 sal_uInt16 nPrefix, 97 const OUString& rLocalName, 98 Reference<com::sun::star::xforms::XDataTypeRepository>& rRepository, 99 const OUString& sTypeName ) : 100 TokenContext( rImport, nPrefix, rLocalName, aAttributes, aChildren ), 101 mxRepository( rRepository ), 102 msTypeName( sTypeName ), 103 msBaseName() 104 { 105 DBG_ASSERT( mxRepository.is(), "need repository" ); 106 } 107 108 SchemaRestrictionContext::~SchemaRestrictionContext() 109 { 110 } 111 112 void SchemaRestrictionContext::CreateDataType() 113 { 114 // only do something if we don't have a data type already 115 if( mxDataType.is() ) 116 return; 117 118 DBG_ASSERT( msBaseName.getLength() > 0, "no base name?" ); 119 DBG_ASSERT( mxRepository.is(), "no repository?" ); 120 121 try 122 { 123 mxDataType = 124 Reference<XPropertySet>( 125 mxRepository->cloneDataType( 126 lcl_getBasicTypeName( mxRepository, 127 GetImport().GetNamespaceMap(), 128 msBaseName ), 129 msTypeName ), 130 UNO_QUERY ); 131 } 132 catch( const Exception& ) 133 { 134 DBG_ERROR( "exception during type creation" ); 135 } 136 DBG_ASSERT( mxDataType.is(), "can't create type" ); 137 } 138 139 void SchemaRestrictionContext::HandleAttribute( 140 sal_uInt16 nToken, 141 const OUString& rValue ) 142 { 143 if( nToken == XML_BASE ) 144 { 145 msBaseName = rValue; 146 } 147 } 148 149 typedef Any (*convert_t)( const OUString& ); 150 151 Any lcl_string( const OUString& rValue ) 152 { 153 return makeAny( rValue ); 154 } 155 156 Any lcl_int32( const OUString& rValue ) 157 { 158 sal_Int32 nValue; 159 bool bSuccess = SvXMLUnitConverter::convertNumber( nValue, rValue ); 160 return bSuccess ? makeAny( nValue ) : Any(); 161 } 162 163 Any lcl_int16( const OUString& rValue ) 164 { 165 sal_Int32 nValue; 166 bool bSuccess = SvXMLUnitConverter::convertNumber( nValue, rValue ); 167 return bSuccess ? makeAny( static_cast<sal_Int16>( nValue ) ) : Any(); 168 } 169 170 Any lcl_whitespace( const OUString& rValue ) 171 { 172 Any aValue; 173 if( IsXMLToken( rValue, XML_PRESERVE ) ) 174 aValue <<= com::sun::star::xsd::WhiteSpaceTreatment::Preserve; 175 else if( IsXMLToken( rValue, XML_REPLACE ) ) 176 aValue <<= com::sun::star::xsd::WhiteSpaceTreatment::Replace; 177 else if( IsXMLToken( rValue, XML_COLLAPSE ) ) 178 aValue <<= com::sun::star::xsd::WhiteSpaceTreatment::Collapse; 179 return aValue; 180 } 181 182 Any lcl_double( const OUString& rValue ) 183 { 184 double fValue; 185 bool bSuccess = SvXMLUnitConverter::convertDouble( fValue, rValue ); 186 return bSuccess ? makeAny( fValue ) : Any(); 187 } 188 189 Any lcl_date( const OUString& rValue ) 190 { 191 Any aAny; 192 193 // parse ISO date 194 sal_Int32 nPos1 = rValue.indexOf( sal_Unicode('-') ); 195 sal_Int32 nPos2 = rValue.indexOf( sal_Unicode('-'), nPos1 + 1 ); 196 if( nPos1 > 0 && nPos2 > 0 ) 197 { 198 Date aDate; 199 aDate.Year = static_cast<sal_uInt16>( 200 rValue.copy( 0, nPos1 ).toInt32() ); 201 aDate.Month = static_cast<sal_uInt16>( 202 rValue.copy( nPos1 + 1, nPos2 - nPos1 - 1 ).toInt32() ); 203 aDate.Day = static_cast<sal_uInt16>( 204 rValue.copy( nPos2 + 1 ).toInt32() ); 205 aAny <<= aDate; 206 } 207 return aAny; 208 } 209 210 Any lcl_dateTime( const OUString& rValue ) 211 { 212 DateTime aDateTime; 213 bool bSuccess = SvXMLUnitConverter::convertDateTime( aDateTime, rValue ); 214 return bSuccess ? makeAny( aDateTime ) : Any(); 215 } 216 217 Any lcl_time( const OUString& rValue ) 218 { 219 Any aAny; 220 DateTime aDateTime; 221 if( SvXMLUnitConverter::convertTime( aDateTime, rValue ) ) 222 { 223 com::sun::star::util::Time aTime; 224 aTime.Hours = aDateTime.Hours; 225 aTime.Minutes = aDateTime.Minutes; 226 aTime.Seconds = aDateTime.Seconds; 227 aTime.HundredthSeconds = aDateTime.HundredthSeconds; 228 aAny <<= aTime; 229 } 230 return aAny; 231 } 232 233 234 SvXMLImportContext* SchemaRestrictionContext::HandleChild( 235 sal_uInt16 nToken, 236 sal_uInt16 nPrefix, 237 const OUString& rLocalName, 238 const Reference<XAttributeList>& xAttrList ) 239 { 240 // find value 241 OUString sValue; 242 sal_Int16 nLength = xAttrList->getLength(); 243 for( sal_Int16 n = 0; n < nLength; n++ ) 244 { 245 if( IsXMLToken( xAttrList->getNameByIndex( n ), XML_VALUE ) ) 246 sValue = xAttrList->getValueByIndex( n ); 247 } 248 249 // determine property name + suitable converter 250 OUString sPropertyName; 251 convert_t pConvert = NULL; 252 switch( nToken ) 253 { 254 case XML_LENGTH: 255 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("Length")); 256 pConvert = &lcl_int32; 257 break; 258 case XML_MINLENGTH: 259 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MinLength")); 260 pConvert = &lcl_int32; 261 break; 262 case XML_MAXLENGTH: 263 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MaxLength")); 264 pConvert = &lcl_int32; 265 break; 266 case XML_TOTALDIGITS: 267 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("TotalDigits")); 268 pConvert = &lcl_int32; 269 break; 270 case XML_FRACTIONDIGITS: 271 sPropertyName =OUString(RTL_CONSTASCII_USTRINGPARAM("FractionDigits")); 272 pConvert = &lcl_int32; 273 break; 274 case XML_PATTERN: 275 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("Pattern")); 276 pConvert = &lcl_string; 277 break; 278 case XML_WHITESPACE: 279 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("WhiteSpace")); 280 pConvert = &lcl_whitespace; 281 break; 282 case XML_MININCLUSIVE: 283 case XML_MINEXCLUSIVE: 284 case XML_MAXINCLUSIVE: 285 case XML_MAXEXCLUSIVE: 286 { 287 // these attributes are mapped to different properties. 288 // To determine the property name, we use an attribute 289 // dependent prefix and a type dependent suffix. The 290 // converter is only type dependent. 291 292 // first, attribute-dependent prefix 293 switch( nToken ) 294 { 295 case XML_MININCLUSIVE: 296 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MinInclusive")); 297 break; 298 case XML_MINEXCLUSIVE: 299 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MinExclusive")); 300 break; 301 case XML_MAXINCLUSIVE: 302 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MaxInclusive")); 303 break; 304 case XML_MAXEXCLUSIVE: 305 sPropertyName = OUString(RTL_CONSTASCII_USTRINGPARAM("MaxExclusive")); 306 break; 307 } 308 309 // second, type-dependent suffix + converter 310 switch( lcl_getTypeClass( mxRepository, 311 GetImport().GetNamespaceMap(), 312 msBaseName ) ) 313 { 314 case com::sun::star::xsd::DataTypeClass::DECIMAL: 315 case com::sun::star::xsd::DataTypeClass::DOUBLE: 316 case com::sun::star::xsd::DataTypeClass::FLOAT: 317 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("Double")); 318 pConvert = &lcl_double; 319 break; 320 case com::sun::star::xsd::DataTypeClass::DATETIME: 321 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("DateTime")); 322 pConvert = &lcl_dateTime; 323 break; 324 case com::sun::star::xsd::DataTypeClass::DATE: 325 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("Date")); 326 pConvert = &lcl_date; 327 break; 328 case com::sun::star::xsd::DataTypeClass::TIME: 329 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("Time")); 330 pConvert = &lcl_time; 331 break; 332 case com::sun::star::xsd::DataTypeClass::gYear: 333 case com::sun::star::xsd::DataTypeClass::gDay: 334 case com::sun::star::xsd::DataTypeClass::gMonth: 335 sPropertyName += OUString(RTL_CONSTASCII_USTRINGPARAM("Int")); 336 pConvert = &lcl_int16; 337 break; 338 339 case com::sun::star::xsd::DataTypeClass::STRING: 340 case com::sun::star::xsd::DataTypeClass::anyURI: 341 case com::sun::star::xsd::DataTypeClass::BOOLEAN: 342 // invalid: These shouldn't have min/max-inclusive 343 break; 344 345 /* data types not yet supported: 346 case com::sun::star::xsd::DataTypeClass::DURATION: 347 case com::sun::star::xsd::DataTypeClass::gYearMonth: 348 case com::sun::star::xsd::DataTypeClass::gMonthDay: 349 case com::sun::star::xsd::DataTypeClass::hexBinary: 350 case com::sun::star::xsd::DataTypeClass::base64Binary: 351 case com::sun::star::xsd::DataTypeClass::QName: 352 case com::sun::star::xsd::DataTypeClass::NOTATION: 353 */ 354 } 355 } 356 break; 357 358 default: 359 DBG_ERROR( "unknown facet" ); 360 } 361 362 // finally, set the property 363 CreateDataType(); 364 if( mxDataType.is() 365 && sPropertyName.getLength() > 0 366 && pConvert != NULL 367 && mxDataType->getPropertySetInfo()->hasPropertyByName(sPropertyName) ) 368 { 369 try 370 { 371 mxDataType->setPropertyValue( sPropertyName, pConvert( sValue ) ); 372 } 373 catch( const Exception& ) 374 { 375 ; // can't set property? Then ignore. 376 } 377 } 378 379 return new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); 380 } 381