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 static rtl::OUString decodeValue( const rtl::OUString & rValue ) 210 { 211 rtl::OUStringBuffer aResult; 212 const sal_Unicode * pValue = rValue.getStr(); 213 214 sal_Int32 nPos = 0; 215 sal_Int32 nEnd = rValue.getLength(); 216 217 while ( nPos < nEnd ) 218 { 219 sal_Unicode c = pValue[ nPos ]; 220 221 if ( '%' == c ) 222 { 223 nPos++; 224 225 if ( nPos == nEnd ) 226 { 227 OSL_ENSURE( sal_False, 228 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 229 return rtl::OUString(); 230 } 231 232 c = pValue[ nPos ]; 233 234 if ( 'p' == c ) 235 { 236 // %per; 237 238 if ( nPos > nEnd - 4 ) 239 { 240 OSL_ENSURE( sal_False, 241 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 242 return rtl::OUString(); 243 } 244 245 if ( ( 'e' == pValue[ nPos + 1 ] ) 246 && 247 ( 'r' == pValue[ nPos + 2 ] ) 248 && 249 ( ';' == pValue[ nPos + 3 ] ) ) 250 { 251 aResult.append( sal_Unicode( '%' ) ); 252 nPos += 3; 253 } 254 else 255 { 256 OSL_ENSURE( sal_False, 257 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 258 return rtl::OUString(); 259 } 260 } 261 else if ( 'l' == c ) 262 { 263 // %lt; 264 265 if ( nPos > nEnd - 3 ) 266 { 267 OSL_ENSURE( sal_False, 268 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 269 return rtl::OUString(); 270 } 271 272 if ( ( 't' == pValue[ nPos + 1 ] ) 273 && 274 ( ';' == pValue[ nPos + 2 ] ) ) 275 { 276 aResult.append( sal_Unicode( '<' ) ); 277 nPos += 2; 278 } 279 else 280 { 281 OSL_ENSURE( sal_False, 282 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 283 return rtl::OUString(); 284 } 285 } 286 else if ( 'g' == c ) 287 { 288 // %gt; 289 290 if ( nPos > nEnd - 3 ) 291 { 292 OSL_ENSURE( sal_False, 293 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 294 return rtl::OUString(); 295 } 296 297 if ( ( 't' == pValue[ nPos + 1 ] ) 298 && 299 ( ';' == pValue[ nPos + 2 ] ) ) 300 { 301 aResult.append( sal_Unicode( '>' ) ); 302 nPos += 2; 303 } 304 else 305 { 306 OSL_ENSURE( sal_False, 307 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 308 return rtl::OUString(); 309 } 310 } 311 else 312 { 313 OSL_ENSURE( sal_False, 314 "UCBDeadPropertyValue::decodeValue - syntax error!" ); 315 return rtl::OUString(); 316 } 317 } 318 else 319 aResult.append( c ); 320 321 nPos++; 322 } 323 324 return rtl::OUString( aResult ); 325 } 326 327 ////////////////////////////////////////////////////////////////////////// 328 // static 329 bool UCBDeadPropertyValue::supportsType( const uno::Type & rType ) 330 { 331 if ( ( rType != getCppuType( static_cast< const rtl::OUString * >( 0 ) ) ) 332 && 333 ( rType != getCppuType( static_cast< const sal_Int32 * >( 0 ) ) ) 334 && 335 ( rType != getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) 336 && 337 ( rType != getCppuBooleanType() ) 338 && 339 ( rType != getCppuCharType() ) 340 && 341 ( rType != getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) 342 && 343 ( rType != getCppuType( static_cast< const sal_Int64 * >( 0 ) ) ) 344 && 345 ( rType != getCppuType( static_cast< const float * >( 0 ) ) ) 346 && 347 ( rType != getCppuType( static_cast< const double * >( 0 ) ) ) ) 348 { 349 return false; 350 } 351 352 return true; 353 } 354 355 ////////////////////////////////////////////////////////////////////////// 356 // static 357 bool UCBDeadPropertyValue::createFromXML( const rtl::OString & /*rInData*/, 358 uno::Any & /*rOutData*/ ) 359 { 360 bool success = false; 361 362 /* 363 ne_xml_parser * parser = ne_xml_create(); 364 if ( parser ) 365 { 366 UCBDeadPropertyValueParseContext aCtx; 367 ne_xml_push_handler( parser, 368 UCBDeadPropertyValue_startelement_callback, 369 UCBDeadPropertyValue_chardata_callback, 370 UCBDeadPropertyValue_endelement_callback, 371 &aCtx ); 372 373 ne_xml_parse( parser, rInData.getStr(), rInData.getLength() ); 374 375 success = !ne_xml_failed( parser ); 376 377 ne_xml_destroy( parser ); 378 379 if ( success ) 380 { 381 if ( aCtx.pType && aCtx.pValue ) 382 { 383 // Decode aCtx.pValue! It may contain XML reserved chars. 384 rtl::OUString aStringValue = decodeValue( *aCtx.pValue ); 385 if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeString ) ) 386 { 387 rOutData <<= aStringValue; 388 } 389 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeLong ) ) 390 { 391 rOutData <<= aStringValue.toInt32(); 392 } 393 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeShort ) ) 394 { 395 rOutData <<= sal_Int16( aStringValue.toInt32() ); 396 } 397 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeBoolean ) ) 398 { 399 if ( aStringValue.equalsIgnoreAsciiCase( 400 rtl::OUString::createFromAscii( "true" ) ) ) 401 rOutData <<= sal_Bool( sal_True ); 402 else 403 rOutData <<= sal_Bool( sal_False ); 404 } 405 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeChar ) ) 406 { 407 rOutData <<= aStringValue.toChar(); 408 } 409 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeByte ) ) 410 { 411 rOutData <<= sal_Int8( aStringValue.toChar() ); 412 } 413 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeHyper ) ) 414 { 415 rOutData <<= aStringValue.toInt64(); 416 } 417 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeFloat ) ) 418 { 419 rOutData <<= aStringValue.toFloat(); 420 } 421 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeDouble ) ) 422 { 423 rOutData <<= aStringValue.toDouble(); 424 } 425 else 426 { 427 OSL_ENSURE( sal_False, 428 "UCBDeadPropertyValue::createFromXML - " 429 "Unsupported property type!" ); 430 success = false; 431 } 432 } 433 else 434 success = false; 435 } 436 } 437 */ 438 return success; 439 } 440 441 ////////////////////////////////////////////////////////////////////////// 442 // static 443 bool UCBDeadPropertyValue::toXML( const uno::Any & rInData, 444 rtl::OUString & rOutData ) 445 { 446 // <ucbprop><type>the_type</type><value>the_value</value></ucbprop> 447 448 // Check property type. Extract type and value as string. 449 450 const uno::Type& rType = rInData.getValueType(); 451 rtl::OUString aStringValue; 452 rtl::OUString aStringType; 453 454 if ( rType == getCppuType( static_cast< const rtl::OUString * >( 0 ) ) ) 455 { 456 // string 457 rInData >>= aStringValue; 458 aStringType = aTypeString; 459 } 460 else if ( rType == getCppuType( static_cast< const sal_Int32 * >( 0 ) ) ) 461 { 462 // long 463 sal_Int32 nValue = 0; 464 rInData >>= nValue; 465 aStringValue = rtl::OUString::valueOf( nValue ); 466 aStringType = aTypeLong; 467 } 468 else if ( rType == getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) 469 { 470 // short 471 sal_Int32 nValue = 0; 472 rInData >>= nValue; 473 aStringValue = rtl::OUString::valueOf( nValue ); 474 aStringType = aTypeShort; 475 } 476 else if ( rType == getCppuBooleanType() ) 477 { 478 // boolean 479 sal_Bool bValue = false; 480 rInData >>= bValue; 481 aStringValue = rtl::OUString::valueOf( bValue ); 482 aStringType = aTypeBoolean; 483 } 484 else if ( rType == getCppuCharType() ) 485 { 486 // char 487 sal_Unicode cValue = 0; 488 rInData >>= cValue; 489 aStringValue = rtl::OUString::valueOf( cValue ); 490 aStringType = aTypeChar; 491 } 492 else if ( rType == getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) 493 { 494 // byte 495 sal_Int8 nValue = 0; 496 rInData >>= nValue; 497 aStringValue = rtl::OUString::valueOf( sal_Unicode( nValue ) ); 498 aStringType = aTypeByte; 499 } 500 else if ( rType == getCppuType( static_cast< const sal_Int64 * >( 0 ) ) ) 501 { 502 // hyper 503 sal_Int64 nValue = 0; 504 rInData >>= nValue; 505 aStringValue = rtl::OUString::valueOf( nValue ); 506 aStringType = aTypeHyper; 507 } 508 else if ( rType == getCppuType( static_cast< const float * >( 0 ) ) ) 509 { 510 // float 511 float nValue = 0; 512 rInData >>= nValue; 513 aStringValue = rtl::OUString::valueOf( nValue ); 514 aStringType = aTypeFloat; 515 } 516 else if ( rType == getCppuType( static_cast< const double * >( 0 ) ) ) 517 { 518 // double 519 double nValue = 0; 520 rInData >>= nValue; 521 aStringValue = rtl::OUString::valueOf( nValue ); 522 aStringType = aTypeDouble; 523 } 524 else 525 { 526 OSL_ENSURE( sal_False, 527 "UCBDeadPropertyValue::toXML - " 528 "Unsupported property type!" ); 529 return false; 530 } 531 532 // Encode value! It must not contain XML reserved chars! 533 aStringValue = encodeValue( aStringValue ); 534 535 rOutData = aXMLPre; 536 rOutData += aStringType; 537 rOutData += aXMLMid; 538 rOutData += aStringValue; 539 rOutData += aXMLEnd; 540 return true; 541 } 542