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_webdav.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
UCBDeadPropertyValueParseContextUCBDeadPropertyValueParseContext43 UCBDeadPropertyValueParseContext() : pType( 0 ), pValue( 0 ) {}
~UCBDeadPropertyValueParseContextUCBDeadPropertyValueParseContext44 ~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 //////////////////////////////////////////////////////////////////////////
encodeValue(const rtl::OUString & rValue)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
supportsType(const uno::Type & rType)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
createFromXML(const rtl::OString &,uno::Any &)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
toXML(const uno::Any & rInData,rtl::OUString & rOutData)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