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_ucb.hxx" 30 31 #include <string.h> 32 #include <ne_xml.h> 33 #include <osl/diagnose.h> 34 #include <rtl/ustrbuf.hxx> 35 #include "UCBDeadPropertyValue.hxx" 36 37 using namespace webdav_ucp; 38 using namespace com::sun::star; 39 40 ////////////////////////////////////////////////////////////////////////// 41 42 struct UCBDeadPropertyValueParseContext 43 { 44 rtl::OUString * pType; 45 rtl::OUString * pValue; 46 47 UCBDeadPropertyValueParseContext() : pType( 0 ), pValue( 0 ) {} 48 ~UCBDeadPropertyValueParseContext() { delete pType; delete pValue; } 49 }; 50 51 // static 52 const rtl::OUString UCBDeadPropertyValue::aTypeString 53 = rtl::OUString::createFromAscii( "string" ); 54 const rtl::OUString UCBDeadPropertyValue::aTypeLong 55 = rtl::OUString::createFromAscii( "long" ); 56 const rtl::OUString UCBDeadPropertyValue::aTypeShort 57 = rtl::OUString::createFromAscii( "short" ); 58 const rtl::OUString UCBDeadPropertyValue::aTypeBoolean 59 = rtl::OUString::createFromAscii( "boolean" ); 60 const rtl::OUString UCBDeadPropertyValue::aTypeChar 61 = rtl::OUString::createFromAscii( "char" ); 62 const rtl::OUString UCBDeadPropertyValue::aTypeByte 63 = rtl::OUString::createFromAscii( "byte" ); 64 const rtl::OUString UCBDeadPropertyValue::aTypeHyper 65 = rtl::OUString::createFromAscii( "hyper" ); 66 const rtl::OUString UCBDeadPropertyValue::aTypeFloat 67 = rtl::OUString::createFromAscii( "float" ); 68 const rtl::OUString UCBDeadPropertyValue::aTypeDouble 69 = rtl::OUString::createFromAscii( "double" ); 70 71 // static 72 const rtl::OUString UCBDeadPropertyValue::aXMLPre 73 = rtl::OUString::createFromAscii( "<ucbprop><type>" ); 74 const rtl::OUString UCBDeadPropertyValue::aXMLMid 75 = rtl::OUString::createFromAscii( "</type><value>" ); 76 const rtl::OUString UCBDeadPropertyValue::aXMLEnd 77 = rtl::OUString::createFromAscii( "</value></ucbprop>" ); 78 79 #define STATE_TOP (1) 80 81 #define STATE_UCBPROP (STATE_TOP) 82 #define STATE_TYPE (STATE_TOP + 1) 83 #define STATE_VALUE (STATE_TOP + 2) 84 85 ////////////////////////////////////////////////////////////////////////// 86 extern "C" int UCBDeadPropertyValue_startelement_callback( 87 void *, 88 int parent, 89 const char * /*nspace*/, 90 const char *name, 91 const char ** ) 92 { 93 if ( name != 0 ) 94 { 95 switch ( parent ) 96 { 97 case NE_XML_STATEROOT: 98 if ( strcmp( name, "ucbprop" ) == 0 ) 99 return STATE_UCBPROP; 100 break; 101 102 case STATE_UCBPROP: 103 if ( strcmp( name, "type" ) == 0 ) 104 return STATE_TYPE; 105 else if ( strcmp( name, "value" ) == 0 ) 106 return STATE_VALUE; 107 break; 108 } 109 } 110 return NE_XML_DECLINE; 111 } 112 113 ////////////////////////////////////////////////////////////////////////// 114 extern "C" int UCBDeadPropertyValue_chardata_callback( 115 void *userdata, 116 int state, 117 const char *buf, 118 size_t len ) 119 { 120 UCBDeadPropertyValueParseContext * pCtx 121 = static_cast< UCBDeadPropertyValueParseContext * >( userdata ); 122 123 switch ( state ) 124 { 125 case STATE_TYPE: 126 OSL_ENSURE( !pCtx->pType, 127 "UCBDeadPropertyValue_endelement_callback - " 128 "Type already set!" ); 129 pCtx->pType 130 = new rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); 131 break; 132 133 case STATE_VALUE: 134 OSL_ENSURE( !pCtx->pValue, 135 "UCBDeadPropertyValue_endelement_callback - " 136 "Value already set!" ); 137 pCtx->pValue 138 = new rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); 139 break; 140 } 141 return 0; // zero to continue, non-zero to abort parsing 142 } 143 144 ////////////////////////////////////////////////////////////////////////// 145 extern "C" int UCBDeadPropertyValue_endelement_callback( 146 void *userdata, 147 int state, 148 const char *, 149 const char * ) 150 { 151 UCBDeadPropertyValueParseContext * pCtx 152 = static_cast< UCBDeadPropertyValueParseContext * >( userdata ); 153 154 switch ( state ) 155 { 156 case STATE_TYPE: 157 if ( !pCtx->pType ) 158 return 1; // abort 159 break; 160 161 case STATE_VALUE: 162 if ( !pCtx->pValue ) 163 return 1; // abort 164 break; 165 166 case STATE_UCBPROP: 167 if ( !pCtx->pType || ! pCtx->pValue ) 168 return 1; // abort 169 break; 170 } 171 return 0; // zero to continue, non-zero to abort parsing 172 } 173 174 ////////////////////////////////////////////////////////////////////////// 175 static rtl::OUString encodeValue( const rtl::OUString & rValue ) 176 { 177 // Note: I do not use the usual & + < + > encoding, because 178 // I want to prevent any XML parser from trying to 'understand' 179 // the value. This caused problems: 180 // 181 // Example: 182 // - Unencoded property value: x<z 183 // PROPPATCH: 184 // - Encoded property value: x<z 185 // - UCBDeadPropertyValue::toXML result: 186 // <ucbprop><type>string</type><value>x<z</value></ucbprop> 187 // PROPFIND: 188 // - parser replaces < by > ==> error (not well formed) 189 190 rtl::OUStringBuffer aResult; 191 const sal_Unicode * pValue = rValue.getStr(); 192 193 sal_Int32 nCount = rValue.getLength(); 194 for ( sal_Int32 n = 0; n < nCount; ++n ) 195 { 196 const sal_Unicode c = pValue[ n ]; 197 198 if ( '%' == c ) 199 aResult.appendAscii( "%per;" ); 200 else if ( '<' == c ) 201 aResult.appendAscii( "%lt;" ); 202 else if ( '>' == c ) 203 aResult.appendAscii( "%gt;" ); 204 else 205 aResult.append( c ); 206 } 207 return rtl::OUString( aResult ); 208 } 209 210 ////////////////////////////////////////////////////////////////////////// 211 static rtl::OUString decodeValue( const rtl::OUString & rValue ) 212 { 213 rtl::OUStringBuffer aResult; 214 const sal_Unicode * pValue = rValue.getStr(); 215 216 sal_Int32 nPos = 0; 217 sal_Int32 nEnd = rValue.getLength(); 218 219 while ( nPos < nEnd ) 220 { 221 sal_Unicode c = pValue[ nPos ]; 222 223 if ( '%' == c ) 224 { 225 nPos++; 226 227 if ( nPos == nEnd ) 228 { 229 OSL_ENSURE( sal_False, 230 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 231 return rtl::OUString(); 232 } 233 234 c = pValue[ nPos ]; 235 236 if ( 'p' == c ) 237 { 238 // %per; 239 240 if ( nPos > nEnd - 4 ) 241 { 242 OSL_ENSURE( sal_False, 243 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 244 return rtl::OUString(); 245 } 246 247 if ( ( 'e' == pValue[ nPos + 1 ] ) 248 && 249 ( 'r' == pValue[ nPos + 2 ] ) 250 && 251 ( ';' == pValue[ nPos + 3 ] ) ) 252 { 253 aResult.append( sal_Unicode( '%' ) ); 254 nPos += 3; 255 } 256 else 257 { 258 OSL_ENSURE( sal_False, 259 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 260 return rtl::OUString(); 261 } 262 } 263 else if ( 'l' == c ) 264 { 265 // %lt; 266 267 if ( nPos > nEnd - 3 ) 268 { 269 OSL_ENSURE( sal_False, 270 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 271 return rtl::OUString(); 272 } 273 274 if ( ( 't' == pValue[ nPos + 1 ] ) 275 && 276 ( ';' == pValue[ nPos + 2 ] ) ) 277 { 278 aResult.append( sal_Unicode( '<' ) ); 279 nPos += 2; 280 } 281 else 282 { 283 OSL_ENSURE( sal_False, 284 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 285 return rtl::OUString(); 286 } 287 } 288 else if ( 'g' == c ) 289 { 290 // %gt; 291 292 if ( nPos > nEnd - 3 ) 293 { 294 OSL_ENSURE( sal_False, 295 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 296 return rtl::OUString(); 297 } 298 299 if ( ( 't' == pValue[ nPos + 1 ] ) 300 && 301 ( ';' == pValue[ nPos + 2 ] ) ) 302 { 303 aResult.append( sal_Unicode( '>' ) ); 304 nPos += 2; 305 } 306 else 307 { 308 OSL_ENSURE( sal_False, 309 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 310 return rtl::OUString(); 311 } 312 } 313 else 314 { 315 OSL_ENSURE( sal_False, 316 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 317 return rtl::OUString(); 318 } 319 } 320 else 321 aResult.append( c ); 322 323 nPos++; 324 } 325 326 return rtl::OUString( aResult ); 327 } 328 329 ////////////////////////////////////////////////////////////////////////// 330 // static 331 bool UCBDeadPropertyValue::supportsType( const uno::Type & rType ) 332 { 333 if ( ( rType != getCppuType( static_cast< const rtl::OUString * >( 0 ) ) ) 334 && 335 ( rType != getCppuType( static_cast< const sal_Int32 * >( 0 ) ) ) 336 && 337 ( rType != getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) 338 && 339 ( rType != getCppuBooleanType() ) 340 && 341 ( rType != getCppuCharType() ) 342 && 343 ( rType != getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) 344 && 345 ( rType != getCppuType( static_cast< const sal_Int64 * >( 0 ) ) ) 346 && 347 ( rType != getCppuType( static_cast< const float * >( 0 ) ) ) 348 && 349 ( rType != getCppuType( static_cast< const double * >( 0 ) ) ) ) 350 { 351 return false; 352 } 353 354 return true; 355 } 356 357 ////////////////////////////////////////////////////////////////////////// 358 // static 359 bool UCBDeadPropertyValue::createFromXML( const rtl::OString & rInData, 360 uno::Any & rOutData ) 361 { 362 bool success = false; 363 364 ne_xml_parser * parser = ne_xml_create(); 365 if ( parser ) 366 { 367 UCBDeadPropertyValueParseContext aCtx; 368 ne_xml_push_handler( parser, 369 UCBDeadPropertyValue_startelement_callback, 370 UCBDeadPropertyValue_chardata_callback, 371 UCBDeadPropertyValue_endelement_callback, 372 &aCtx ); 373 374 ne_xml_parse( parser, rInData.getStr(), rInData.getLength() ); 375 376 success = !ne_xml_failed( parser ); 377 378 ne_xml_destroy( parser ); 379 380 if ( success ) 381 { 382 if ( aCtx.pType && aCtx.pValue ) 383 { 384 // Decode aCtx.pValue! It may contain XML reserved chars. 385 rtl::OUString aStringValue = decodeValue( *aCtx.pValue ); 386 if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeString ) ) 387 { 388 rOutData <<= aStringValue; 389 } 390 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeLong ) ) 391 { 392 rOutData <<= aStringValue.toInt32(); 393 } 394 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeShort ) ) 395 { 396 rOutData <<= sal_Int16( aStringValue.toInt32() ); 397 } 398 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeBoolean ) ) 399 { 400 if ( aStringValue.equalsIgnoreAsciiCase( 401 rtl::OUString::createFromAscii( "true" ) ) ) 402 rOutData <<= sal_Bool( sal_True ); 403 else 404 rOutData <<= sal_Bool( sal_False ); 405 } 406 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeChar ) ) 407 { 408 rOutData <<= aStringValue.toChar(); 409 } 410 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeByte ) ) 411 { 412 rOutData <<= sal_Int8( aStringValue.toChar() ); 413 } 414 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeHyper ) ) 415 { 416 rOutData <<= aStringValue.toInt64(); 417 } 418 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeFloat ) ) 419 { 420 rOutData <<= aStringValue.toFloat(); 421 } 422 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeDouble ) ) 423 { 424 rOutData <<= aStringValue.toDouble(); 425 } 426 else 427 { 428 OSL_ENSURE( sal_False, 429 "UCBDeadPropertyValue::createFromXML - " 430 "Unsupported property type!" ); 431 success = false; 432 } 433 } 434 else 435 success = false; 436 } 437 } 438 439 return success; 440 } 441 442 ////////////////////////////////////////////////////////////////////////// 443 // static 444 bool UCBDeadPropertyValue::toXML( const uno::Any & rInData, 445 rtl::OUString & rOutData ) 446 { 447 // <ucbprop><type>the_type</type><value>the_value</value></ucbprop> 448 449 // Check property type. Extract type and value as string. 450 451 const uno::Type& rType = rInData.getValueType(); 452 rtl::OUString aStringValue; 453 rtl::OUString aStringType; 454 455 if ( rType == getCppuType( static_cast< const rtl::OUString * >( 0 ) ) ) 456 { 457 // string 458 rInData >>= aStringValue; 459 aStringType = aTypeString; 460 } 461 else if ( rType == getCppuType( static_cast< const sal_Int32 * >( 0 ) ) ) 462 { 463 // long 464 sal_Int32 nValue = 0; 465 rInData >>= nValue; 466 aStringValue = rtl::OUString::valueOf( nValue ); 467 aStringType = aTypeLong; 468 } 469 else if ( rType == getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) 470 { 471 // short 472 sal_Int32 nValue = 0; 473 rInData >>= nValue; 474 aStringValue = rtl::OUString::valueOf( nValue ); 475 aStringType = aTypeShort; 476 } 477 else if ( rType == getCppuBooleanType() ) 478 { 479 // boolean 480 sal_Bool bValue = false; 481 rInData >>= bValue; 482 aStringValue = rtl::OUString::valueOf( bValue ); 483 aStringType = aTypeBoolean; 484 } 485 else if ( rType == getCppuCharType() ) 486 { 487 // char 488 sal_Unicode cValue = 0; 489 rInData >>= cValue; 490 aStringValue = rtl::OUString::valueOf( cValue ); 491 aStringType = aTypeChar; 492 } 493 else if ( rType == getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) 494 { 495 // byte 496 sal_Int8 nValue = 0; 497 rInData >>= nValue; 498 aStringValue = rtl::OUString::valueOf( sal_Unicode( nValue ) ); 499 aStringType = aTypeByte; 500 } 501 else if ( rType == getCppuType( static_cast< const sal_Int64 * >( 0 ) ) ) 502 { 503 // hyper 504 sal_Int64 nValue = 0; 505 rInData >>= nValue; 506 aStringValue = rtl::OUString::valueOf( nValue ); 507 aStringType = aTypeHyper; 508 } 509 else if ( rType == getCppuType( static_cast< const float * >( 0 ) ) ) 510 { 511 // float 512 float nValue = 0; 513 rInData >>= nValue; 514 aStringValue = rtl::OUString::valueOf( nValue ); 515 aStringType = aTypeFloat; 516 } 517 else if ( rType == getCppuType( static_cast< const double * >( 0 ) ) ) 518 { 519 // double 520 double nValue = 0; 521 rInData >>= nValue; 522 aStringValue = rtl::OUString::valueOf( nValue ); 523 aStringType = aTypeDouble; 524 } 525 else 526 { 527 OSL_ENSURE( sal_False, 528 "UCBDeadPropertyValue::toXML - " 529 "Unsupported property type!" ); 530 return false; 531 } 532 533 // Encode value! It must not contain XML reserved chars! 534 aStringValue = encodeValue( aStringValue ); 535 536 rOutData = aXMLPre; 537 rOutData += aStringType; 538 rOutData += aXMLMid; 539 rOutData += aStringValue; 540 rOutData += aXMLEnd; 541 542 return true; 543 } 544