bump product version to 5.0.4.1
[LibreOffice.git] / ucb / source / ucp / webdav-neon / UCBDeadPropertyValue.cxx
bloba7377669752501ed8cfbacc4bb86e5ce966c0816
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <config_lgpl.h>
30 #include <string.h>
31 #include <ne_xml.h>
32 #include <osl/diagnose.h>
33 #include <rtl/ustrbuf.hxx>
34 #include "UCBDeadPropertyValue.hxx"
36 using namespace webdav_ucp;
37 using namespace com::sun::star;
41 struct UCBDeadPropertyValueParseContext
43 OUString * pType;
44 OUString * pValue;
46 UCBDeadPropertyValueParseContext() : pType( 0 ), pValue( 0 ) {}
47 ~UCBDeadPropertyValueParseContext() { delete pType; delete pValue; }
50 // static
51 const OUString UCBDeadPropertyValue::aTypeString("string");
52 const OUString UCBDeadPropertyValue::aTypeLong("long");
53 const OUString UCBDeadPropertyValue::aTypeShort("short");
54 const OUString UCBDeadPropertyValue::aTypeBoolean("boolean");
55 const OUString UCBDeadPropertyValue::aTypeChar("char");
56 const OUString UCBDeadPropertyValue::aTypeByte("byte");
57 const OUString UCBDeadPropertyValue::aTypeHyper("hyper");
58 const OUString UCBDeadPropertyValue::aTypeFloat("float");
59 const OUString UCBDeadPropertyValue::aTypeDouble("double");
61 // static
62 const OUString UCBDeadPropertyValue::aXMLPre("<ucbprop><type>");
63 const OUString UCBDeadPropertyValue::aXMLMid("</type><value>");
64 const OUString UCBDeadPropertyValue::aXMLEnd("</value></ucbprop>");
66 #define STATE_TOP (1)
68 #define STATE_UCBPROP (STATE_TOP)
69 #define STATE_TYPE (STATE_TOP + 1)
70 #define STATE_VALUE (STATE_TOP + 2)
73 extern "C" int UCBDeadPropertyValue_startelement_callback(
74 void *,
75 int parent,
76 const char * /*nspace*/,
77 const char *name,
78 const char ** )
80 if ( name != 0 )
82 switch ( parent )
84 case NE_XML_STATEROOT:
85 if ( strcmp( name, "ucbprop" ) == 0 )
86 return STATE_UCBPROP;
87 break;
89 case STATE_UCBPROP:
90 if ( strcmp( name, "type" ) == 0 )
91 return STATE_TYPE;
92 else if ( strcmp( name, "value" ) == 0 )
93 return STATE_VALUE;
94 break;
97 return NE_XML_DECLINE;
101 extern "C" int UCBDeadPropertyValue_chardata_callback(
102 void *userdata,
103 int state,
104 const char *buf,
105 size_t len )
107 UCBDeadPropertyValueParseContext * pCtx
108 = static_cast< UCBDeadPropertyValueParseContext * >( userdata );
110 switch ( state )
112 case STATE_TYPE:
113 OSL_ENSURE( !pCtx->pType,
114 "UCBDeadPropertyValue_endelement_callback - "
115 "Type already set!" );
116 pCtx->pType
117 = new OUString( buf, len, RTL_TEXTENCODING_ASCII_US );
118 break;
120 case STATE_VALUE:
121 OSL_ENSURE( !pCtx->pValue,
122 "UCBDeadPropertyValue_endelement_callback - "
123 "Value already set!" );
124 pCtx->pValue
125 = new OUString( buf, len, RTL_TEXTENCODING_ASCII_US );
126 break;
128 return 0; // zero to continue, non-zero to abort parsing
132 extern "C" int UCBDeadPropertyValue_endelement_callback(
133 void *userdata,
134 int state,
135 const char *,
136 const char * )
138 UCBDeadPropertyValueParseContext * pCtx
139 = static_cast< UCBDeadPropertyValueParseContext * >( userdata );
141 switch ( state )
143 case STATE_TYPE:
144 if ( !pCtx->pType )
145 return 1; // abort
146 break;
148 case STATE_VALUE:
149 if ( !pCtx->pValue )
150 return 1; // abort
151 break;
153 case STATE_UCBPROP:
154 if ( !pCtx->pType || ! pCtx->pValue )
155 return 1; // abort
156 break;
158 return 0; // zero to continue, non-zero to abort parsing
162 static OUString encodeValue( const OUString & rValue )
164 // Note: I do not use the usual &amp; + &lt; + &gt; encoding, because
165 // I want to prevent any XML parser from trying to 'understand'
166 // the value. This caused problems:
168 // Example:
169 // - Unencoded property value: x<z
170 // PROPPATCH:
171 // - Encoded property value: x&lt;z
172 // - UCBDeadPropertyValue::toXML result:
173 // <ucbprop><type>string</type><value>x&lt;z</value></ucbprop>
174 // PROPFIND:
175 // - parser replaces &lt; by > ==> error (not well formed)
177 OUStringBuffer aResult;
178 const sal_Unicode * pValue = rValue.getStr();
180 sal_Int32 nCount = rValue.getLength();
181 for ( sal_Int32 n = 0; n < nCount; ++n )
183 const sal_Unicode c = pValue[ n ];
185 if ( '%' == c )
186 aResult.appendAscii( "%per;" );
187 else if ( '<' == c )
188 aResult.appendAscii( "%lt;" );
189 else if ( '>' == c )
190 aResult.appendAscii( "%gt;" );
191 else
192 aResult.append( c );
194 return aResult.makeStringAndClear();
198 static OUString decodeValue( const OUString & rValue )
200 OUStringBuffer aResult;
201 const sal_Unicode * pValue = rValue.getStr();
203 sal_Int32 nPos = 0;
204 sal_Int32 nEnd = rValue.getLength();
206 while ( nPos < nEnd )
208 sal_Unicode c = pValue[ nPos ];
210 if ( '%' == c )
212 nPos++;
214 if ( nPos == nEnd )
216 OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
217 return OUString();
220 c = pValue[ nPos ];
222 if ( 'p' == c )
224 // %per;
226 if ( nPos > nEnd - 4 )
228 OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
229 return OUString();
232 if ( ( 'e' == pValue[ nPos + 1 ] )
234 ( 'r' == pValue[ nPos + 2 ] )
236 ( ';' == pValue[ nPos + 3 ] ) )
238 aResult.append( '%' );
239 nPos += 3;
241 else
243 OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
244 return OUString();
247 else if ( 'l' == c )
249 // %lt;
251 if ( nPos > nEnd - 3 )
253 OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
254 return OUString();
257 if ( ( 't' == pValue[ nPos + 1 ] )
259 ( ';' == pValue[ nPos + 2 ] ) )
261 aResult.append( '<' );
262 nPos += 2;
264 else
266 OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
267 return OUString();
270 else if ( 'g' == c )
272 // %gt;
274 if ( nPos > nEnd - 3 )
276 OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
277 return OUString();
280 if ( ( 't' == pValue[ nPos + 1 ] )
282 ( ';' == pValue[ nPos + 2 ] ) )
284 aResult.append( '>' );
285 nPos += 2;
287 else
289 OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
290 return OUString();
293 else
295 OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
296 return OUString();
299 else
300 aResult.append( c );
302 nPos++;
305 return aResult.makeStringAndClear();
309 // static
310 bool UCBDeadPropertyValue::supportsType( const uno::Type & rType )
312 if ( ( rType != cppu::UnoType<OUString>::get() )
314 ( rType != cppu::UnoType<sal_Int32>::get() )
316 ( rType != cppu::UnoType<sal_Int16>::get() )
318 ( rType != cppu::UnoType<bool>::get() )
320 ( rType != cppu::UnoType<cppu::UnoCharType>::get() )
322 ( rType != cppu::UnoType<sal_Int8>::get() )
324 ( rType != cppu::UnoType<sal_Int64>::get() )
326 ( rType != cppu::UnoType<float>::get() )
328 ( rType != cppu::UnoType<double>::get() ) )
330 return false;
333 return true;
337 // static
338 bool UCBDeadPropertyValue::createFromXML( const OString & rInData,
339 uno::Any & rOutData )
341 bool success = false;
343 ne_xml_parser * parser = ne_xml_create();
344 if ( parser )
346 UCBDeadPropertyValueParseContext aCtx;
347 ne_xml_push_handler( parser,
348 UCBDeadPropertyValue_startelement_callback,
349 UCBDeadPropertyValue_chardata_callback,
350 UCBDeadPropertyValue_endelement_callback,
351 &aCtx );
353 ne_xml_parse( parser, rInData.getStr(), rInData.getLength() );
355 success = !ne_xml_failed( parser );
357 ne_xml_destroy( parser );
359 if ( success )
361 if ( aCtx.pType && aCtx.pValue )
363 // Decode aCtx.pValue! It may contain XML reserved chars.
364 OUString aStringValue = decodeValue( *aCtx.pValue );
365 if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeString ) )
367 rOutData <<= aStringValue;
369 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeLong ) )
371 rOutData <<= aStringValue.toInt32();
373 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeShort ) )
375 rOutData <<= sal_Int16( aStringValue.toInt32() );
377 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeBoolean ) )
379 if ( aStringValue.equalsIgnoreAsciiCase(
380 OUString("true") ) )
381 rOutData <<= true;
382 else
383 rOutData <<= false;
385 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeChar ) )
387 rOutData <<= aStringValue.toChar();
389 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeByte ) )
391 rOutData <<= sal_Int8( aStringValue.toChar() );
393 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeHyper ) )
395 rOutData <<= aStringValue.toInt64();
397 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeFloat ) )
399 rOutData <<= aStringValue.toFloat();
401 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeDouble ) )
403 rOutData <<= aStringValue.toDouble();
405 else
407 OSL_FAIL( "UCBDeadPropertyValue::createFromXML - "
408 "Unsupported property type!" );
409 success = false;
412 else
413 success = false;
417 return success;
421 // static
422 bool UCBDeadPropertyValue::toXML( const uno::Any & rInData,
423 OUString & rOutData )
425 // <ucbprop><type>the_type</type><value>the_value</value></ucbprop>
427 // Check property type. Extract type and value as string.
429 const uno::Type& rType = rInData.getValueType();
430 OUString aStringValue;
431 OUString aStringType;
433 if ( rType == cppu::UnoType<OUString>::get() )
435 // string
436 rInData >>= aStringValue;
437 aStringType = aTypeString;
439 else if ( rType == cppu::UnoType<sal_Int32>::get() )
441 // long
442 sal_Int32 nValue = 0;
443 rInData >>= nValue;
444 aStringValue = OUString::number( nValue );
445 aStringType = aTypeLong;
447 else if ( rType == cppu::UnoType<sal_Int16>::get() )
449 // short
450 sal_Int32 nValue = 0;
451 rInData >>= nValue;
452 aStringValue = OUString::number( nValue );
453 aStringType = aTypeShort;
455 else if ( rType == cppu::UnoType<bool>::get() )
457 // boolean
458 bool bValue = false;
459 rInData >>= bValue;
460 aStringValue = OUString::boolean( bValue );
461 aStringType = aTypeBoolean;
463 else if ( rType == cppu::UnoType<cppu::UnoCharType>::get() )
465 // char
466 sal_Unicode cValue = 0;
467 rInData >>= cValue;
468 aStringValue = OUString( cValue );
469 aStringType = aTypeChar;
471 else if ( rType == cppu::UnoType<sal_Int8>::get() )
473 // byte
474 sal_Int8 nValue = 0;
475 rInData >>= nValue;
476 aStringValue = OUString( sal_Unicode( nValue ) );
477 aStringType = aTypeByte;
479 else if ( rType == cppu::UnoType<sal_Int64>::get() )
481 // hyper
482 sal_Int64 nValue = 0;
483 rInData >>= nValue;
484 aStringValue = OUString::number( nValue );
485 aStringType = aTypeHyper;
487 else if ( rType == cppu::UnoType<float>::get() )
489 // float
490 float nValue = 0;
491 rInData >>= nValue;
492 aStringValue = OUString::number( nValue );
493 aStringType = aTypeFloat;
495 else if ( rType == cppu::UnoType<double>::get() )
497 // double
498 double nValue = 0;
499 rInData >>= nValue;
500 aStringValue = OUString::number( nValue );
501 aStringType = aTypeDouble;
503 else
505 OSL_FAIL( "UCBDeadPropertyValue::toXML - "
506 "Unsupported property type!" );
507 return false;
510 // Encode value! It must not contain XML reserved chars!
511 aStringValue = encodeValue( aStringValue );
513 rOutData = aXMLPre;
514 rOutData += aStringType;
515 rOutData += aXMLMid;
516 rOutData += aStringValue;
517 rOutData += aXMLEnd;
519 return true;
522 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */