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