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_ucb.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 
43     UCBDeadPropertyValueParseContext() : pType( 0 ), pValue( 0 ) {}
44     ~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 //////////////////////////////////////////////////////////////////////////
173 static rtl::OUString encodeValue( const rtl::OUString & rValue )
174 {
175     // Note: I do not use the usual &amp; + &lt; + &gt; 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&lt;z
183     //       - UCBDeadPropertyValue::toXML result:
184     //              <ucbprop><type>string</type><value>x&lt;z</value></ucbprop>
185     //       PROPFIND:
186     //       - parser replaces &lt; 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 static rtl::OUString decodeValue( const rtl::OUString & rValue )
210 {
211     rtl::OUStringBuffer aResult;
212     const sal_Unicode * pValue = rValue.getStr();
213 
214     sal_Int32 nPos = 0;
215     sal_Int32 nEnd = rValue.getLength();
216 
217     while ( nPos < nEnd )
218     {
219         sal_Unicode c = pValue[ nPos ];
220 
221         if ( '%' == c )
222         {
223             nPos++;
224 
225             if ( nPos == nEnd )
226             {
227                 OSL_ENSURE( sal_False,
228                     "UCBDeadPropertyValue::decodeValue - syntax error!" );
229                 return rtl::OUString();
230             }
231 
232             c = pValue[ nPos ];
233 
234             if ( 'p' == c )
235             {
236                 // %per;
237 
238                 if ( nPos > nEnd - 4 )
239                 {
240                     OSL_ENSURE( sal_False,
241                         "UCBDeadPropertyValue::decodeValue - syntax error!" );
242                     return rtl::OUString();
243                 }
244 
245                 if ( ( 'e' == pValue[ nPos + 1 ] )
246                      &&
247                      ( 'r' == pValue[ nPos + 2 ] )
248                      &&
249                      ( ';' == pValue[ nPos + 3 ] ) )
250                 {
251                     aResult.append( sal_Unicode( '%' ) );
252                     nPos += 3;
253                 }
254                 else
255                 {
256                     OSL_ENSURE( sal_False,
257                         "UCBDeadPropertyValue::decodeValue - syntax error!" );
258                     return rtl::OUString();
259                 }
260             }
261             else if ( 'l' == c )
262             {
263                 // %lt;
264 
265                 if ( nPos > nEnd - 3 )
266                 {
267                     OSL_ENSURE( sal_False,
268                         "UCBDeadPropertyValue::decodeValue - syntax error!" );
269                     return rtl::OUString();
270                 }
271 
272                 if ( ( 't' == pValue[ nPos + 1 ] )
273                      &&
274                      ( ';' == pValue[ nPos + 2 ] ) )
275                 {
276                     aResult.append( sal_Unicode( '<' ) );
277                     nPos += 2;
278                 }
279                 else
280                 {
281                     OSL_ENSURE( sal_False,
282                         "UCBDeadPropertyValue::decodeValue - syntax error!" );
283                     return rtl::OUString();
284                 }
285             }
286             else if ( 'g' == c )
287             {
288                 // %gt;
289 
290                 if ( nPos > nEnd - 3 )
291                 {
292                     OSL_ENSURE( sal_False,
293                         "UCBDeadPropertyValue::decodeValue - syntax error!" );
294                     return rtl::OUString();
295                 }
296 
297                 if ( ( 't' == pValue[ nPos + 1 ] )
298                      &&
299                      ( ';' == pValue[ nPos + 2 ] ) )
300                 {
301                     aResult.append( sal_Unicode( '>' ) );
302                     nPos += 2;
303                 }
304                 else
305                 {
306                     OSL_ENSURE( sal_False,
307                         "UCBDeadPropertyValue::decodeValue - syntax error!" );
308                     return rtl::OUString();
309                 }
310             }
311             else
312             {
313                 OSL_ENSURE( sal_False,
314                     "UCBDeadPropertyValue::decodeValue - syntax error!" );
315                 return rtl::OUString();
316             }
317         }
318         else
319             aResult.append( c );
320 
321         nPos++;
322     }
323 
324     return rtl::OUString( aResult );
325 }
326 
327 //////////////////////////////////////////////////////////////////////////
328 // static
329 bool UCBDeadPropertyValue::supportsType( const uno::Type & rType )
330 {
331     if ( ( rType != getCppuType( static_cast< const rtl::OUString * >( 0 ) ) )
332          &&
333          ( rType != getCppuType( static_cast< const sal_Int32 * >( 0 ) ) )
334          &&
335          ( rType != getCppuType( static_cast< const sal_Int16 * >( 0 ) ) )
336          &&
337          ( rType != getCppuBooleanType() )
338          &&
339          ( rType != getCppuCharType() )
340          &&
341          ( rType != getCppuType( static_cast< const sal_Int8 * >( 0 ) ) )
342          &&
343          ( rType != getCppuType( static_cast< const sal_Int64 * >( 0 ) ) )
344          &&
345          ( rType != getCppuType( static_cast< const float * >( 0 ) ) )
346          &&
347          ( rType != getCppuType( static_cast< const double * >( 0 ) ) ) )
348     {
349         return false;
350     }
351 
352     return true;
353 }
354 
355 //////////////////////////////////////////////////////////////////////////
356 // static
357 bool UCBDeadPropertyValue::createFromXML( const rtl::OString & /*rInData*/,
358                                           uno::Any & /*rOutData*/ )
359 {
360     bool success = false;
361 
362     /*
363     ne_xml_parser * parser = ne_xml_create();
364     if ( parser )
365     {
366         UCBDeadPropertyValueParseContext aCtx;
367         ne_xml_push_handler( parser,
368                              UCBDeadPropertyValue_startelement_callback,
369                              UCBDeadPropertyValue_chardata_callback,
370                              UCBDeadPropertyValue_endelement_callback,
371                              &aCtx );
372 
373         ne_xml_parse( parser, rInData.getStr(), rInData.getLength() );
374 
375         success = !ne_xml_failed( parser );
376 
377         ne_xml_destroy( parser );
378 
379         if ( success )
380         {
381             if ( aCtx.pType && aCtx.pValue )
382             {
383                 // Decode aCtx.pValue! It may contain XML reserved chars.
384                 rtl::OUString aStringValue = decodeValue( *aCtx.pValue );
385                 if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeString ) )
386                 {
387                     rOutData <<= aStringValue;
388                 }
389                 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeLong ) )
390                 {
391                     rOutData <<= aStringValue.toInt32();
392                 }
393                 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeShort ) )
394                 {
395                     rOutData <<= sal_Int16( aStringValue.toInt32() );
396                 }
397                 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeBoolean ) )
398                 {
399                     if ( aStringValue.equalsIgnoreAsciiCase(
400                             rtl::OUString::createFromAscii( "true" ) ) )
401                         rOutData <<= sal_Bool( sal_True );
402                     else
403                         rOutData <<= sal_Bool( sal_False );
404                 }
405                 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeChar ) )
406                 {
407                     rOutData <<= aStringValue.toChar();
408                 }
409                 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeByte ) )
410                 {
411                     rOutData <<= sal_Int8( aStringValue.toChar() );
412                 }
413                 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeHyper ) )
414                 {
415                     rOutData <<= aStringValue.toInt64();
416                 }
417                 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeFloat ) )
418                 {
419                     rOutData <<= aStringValue.toFloat();
420                 }
421                 else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeDouble ) )
422                 {
423                     rOutData <<= aStringValue.toDouble();
424                 }
425                 else
426                 {
427                     OSL_ENSURE( sal_False,
428                                 "UCBDeadPropertyValue::createFromXML - "
429                                 "Unsupported property type!" );
430                     success = false;
431                 }
432             }
433             else
434                 success = false;
435         }
436     }
437     */
438     return success;
439 }
440 
441 //////////////////////////////////////////////////////////////////////////
442 // static
443 bool UCBDeadPropertyValue::toXML( const uno::Any & rInData,
444                                   rtl::OUString & rOutData )
445 {
446     // <ucbprop><type>the_type</type><value>the_value</value></ucbprop>
447 
448     // Check property type. Extract type and value as string.
449 
450     const uno::Type& rType = rInData.getValueType();
451     rtl::OUString aStringValue;
452     rtl::OUString aStringType;
453 
454     if ( rType == getCppuType( static_cast< const rtl::OUString * >( 0 ) ) )
455     {
456         // string
457         rInData >>= aStringValue;
458         aStringType = aTypeString;
459     }
460     else if ( rType == getCppuType( static_cast< const sal_Int32 * >( 0 ) ) )
461     {
462         // long
463         sal_Int32 nValue = 0;
464         rInData >>= nValue;
465         aStringValue = rtl::OUString::valueOf( nValue );
466         aStringType = aTypeLong;
467     }
468     else if ( rType == getCppuType( static_cast< const sal_Int16 * >( 0 ) ) )
469     {
470         // short
471         sal_Int32 nValue = 0;
472         rInData >>= nValue;
473         aStringValue = rtl::OUString::valueOf( nValue );
474         aStringType = aTypeShort;
475     }
476     else if ( rType == getCppuBooleanType() )
477     {
478         // boolean
479         sal_Bool bValue = false;
480         rInData >>= bValue;
481         aStringValue = rtl::OUString::valueOf( bValue );
482         aStringType = aTypeBoolean;
483     }
484     else if ( rType == getCppuCharType() )
485     {
486         // char
487         sal_Unicode cValue = 0;
488         rInData >>= cValue;
489         aStringValue = rtl::OUString::valueOf( cValue );
490         aStringType = aTypeChar;
491     }
492     else if ( rType == getCppuType( static_cast< const sal_Int8 * >( 0 ) ) )
493     {
494         // byte
495         sal_Int8 nValue = 0;
496         rInData >>= nValue;
497         aStringValue = rtl::OUString::valueOf( sal_Unicode( nValue ) );
498         aStringType = aTypeByte;
499     }
500     else if ( rType == getCppuType( static_cast< const sal_Int64 * >( 0 ) ) )
501     {
502         // hyper
503         sal_Int64 nValue = 0;
504         rInData >>= nValue;
505         aStringValue = rtl::OUString::valueOf( nValue );
506         aStringType = aTypeHyper;
507     }
508     else if ( rType == getCppuType( static_cast< const float * >( 0 ) ) )
509     {
510         // float
511         float nValue = 0;
512         rInData >>= nValue;
513         aStringValue = rtl::OUString::valueOf( nValue );
514         aStringType = aTypeFloat;
515     }
516     else if ( rType == getCppuType( static_cast< const double * >( 0 ) ) )
517     {
518         // double
519         double nValue = 0;
520         rInData >>= nValue;
521         aStringValue = rtl::OUString::valueOf( nValue );
522         aStringType = aTypeDouble;
523     }
524     else
525     {
526         OSL_ENSURE( sal_False,
527                     "UCBDeadPropertyValue::toXML - "
528                     "Unsupported property type!" );
529         return false;
530     }
531 
532     // Encode value! It must not contain XML reserved chars!
533     aStringValue = encodeValue( aStringValue );
534 
535     rOutData =  aXMLPre;
536     rOutData += aStringType;
537     rOutData += aXMLMid;
538     rOutData += aStringValue;
539     rOutData += aXMLEnd;
540     return true;
541 }
542