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