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