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