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