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