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