1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 
31 #include "comphelper/anytostring.hxx"
32 #include "osl/diagnose.h"
33 #include "rtl/ustrbuf.hxx"
34 #include "typelib/typedescription.h"
35 #include "com/sun/star/lang/XServiceInfo.hpp"
36 
37 using namespace ::com::sun::star;
38 
39 namespace comphelper {
40 namespace {
41 
42 void appendTypeError(
43     rtl::OUStringBuffer & buf, typelib_TypeDescriptionReference * typeRef )
44 {
45     buf.appendAscii(
46         RTL_CONSTASCII_STRINGPARAM("<cannot get type description of type ") );
47     buf.append( rtl::OUString::unacquired( &typeRef->pTypeName ) );
48     buf.append( static_cast< sal_Unicode >('>') );
49 }
50 
51 inline void appendChar( rtl::OUStringBuffer & buf, sal_Unicode c )
52 {
53     if (c < ' ' || c > '~') {
54         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\X") );
55         rtl::OUString const s(
56             rtl::OUString::valueOf( static_cast< sal_Int32 >(c), 16 ) );
57         for ( sal_Int32 f = 4 - s.getLength(); f > 0; --f )
58             buf.append( static_cast< sal_Unicode >('0') );
59         buf.append( s );
60     }
61     else {
62         buf.append( c );
63     }
64 }
65 
66 //------------------------------------------------------------------------------
67 void appendValue( rtl::OUStringBuffer & buf,
68                   void const * val, typelib_TypeDescriptionReference * typeRef,
69                   bool prependType )
70 {
71     if (typeRef->eTypeClass == typelib_TypeClass_VOID) {
72         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("void") );
73         return;
74     }
75     OSL_ASSERT( val != 0 );
76 
77     if (prependType &&
78         typeRef->eTypeClass != typelib_TypeClass_STRING &&
79         typeRef->eTypeClass != typelib_TypeClass_CHAR &&
80         typeRef->eTypeClass != typelib_TypeClass_BOOLEAN)
81     {
82         buf.append( static_cast< sal_Unicode >('(') );
83         buf.append( rtl::OUString::unacquired( &typeRef->pTypeName ) );
84         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(") ") );
85     }
86 
87     switch (typeRef->eTypeClass) {
88     case typelib_TypeClass_INTERFACE: {
89         buf.append( static_cast<sal_Unicode>('@') );
90         buf.append( reinterpret_cast< sal_Int64 >(
91                         *static_cast< void * const * >(val) ), 16 );
92         uno::Reference< lang::XServiceInfo > xServiceInfo(
93             *static_cast< uno::XInterface * const * >(val),
94             uno::UNO_QUERY );
95         if (xServiceInfo.is()) {
96             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
97                                  " (ImplementationName = \"") );
98             buf.append( xServiceInfo->getImplementationName() );
99             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\")") );
100         }
101         break;
102     }
103     case typelib_TypeClass_STRUCT:
104     case typelib_TypeClass_EXCEPTION: {
105         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
106         typelib_TypeDescription * typeDescr = 0;
107         typelib_typedescriptionreference_getDescription( &typeDescr, typeRef );
108         if (typeDescr == 0 || !typelib_typedescription_complete( &typeDescr )) {
109             appendTypeError( buf, typeRef );
110         }
111         else {
112             typelib_CompoundTypeDescription * compType =
113                 reinterpret_cast< typelib_CompoundTypeDescription * >(
114                     typeDescr );
115             sal_Int32 nDescr = compType->nMembers;
116 
117             if (compType->pBaseTypeDescription) {
118                 appendValue(
119                     buf, val, reinterpret_cast<
120                     typelib_TypeDescription * >(
121                         compType->pBaseTypeDescription)->pWeakRef, false );
122                 if (nDescr > 0)
123                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
124             }
125 
126             typelib_TypeDescriptionReference ** ppTypeRefs =
127                 compType->ppTypeRefs;
128             sal_Int32 * memberOffsets = compType->pMemberOffsets;
129             rtl_uString ** ppMemberNames = compType->ppMemberNames;
130 
131             for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos )
132             {
133                 buf.append( ppMemberNames[ nPos ] );
134                 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" = ") );
135                 typelib_TypeDescription * memberType = 0;
136                 TYPELIB_DANGER_GET( &memberType, ppTypeRefs[ nPos ] );
137                 if (memberType == 0) {
138                     appendTypeError( buf, ppTypeRefs[ nPos ] );
139                 }
140                 else {
141                     appendValue( buf,
142                                  static_cast< char const * >(
143                                      val ) + memberOffsets[ nPos ],
144                                  memberType->pWeakRef, true );
145                     TYPELIB_DANGER_RELEASE( memberType );
146                 }
147                 if (nPos < (nDescr - 1))
148                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
149             }
150         }
151         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
152         if (typeDescr != 0)
153             typelib_typedescription_release( typeDescr );
154         break;
155     }
156     case typelib_TypeClass_SEQUENCE: {
157         typelib_TypeDescription * typeDescr = 0;
158         TYPELIB_DANGER_GET( &typeDescr, typeRef );
159         if (typeDescr == 0) {
160             appendTypeError( buf,typeRef );
161         }
162         else {
163             typelib_TypeDescriptionReference * elementTypeRef =
164                 reinterpret_cast<
165                 typelib_IndirectTypeDescription * >(typeDescr)->pType;
166             typelib_TypeDescription * elementTypeDescr = 0;
167             TYPELIB_DANGER_GET( &elementTypeDescr, elementTypeRef );
168             if (elementTypeDescr == 0)
169             {
170                 appendTypeError( buf, elementTypeRef );
171             }
172             else
173             {
174                 sal_Int32 nElementSize = elementTypeDescr->nSize;
175                 uno_Sequence * seq =
176                     *static_cast< uno_Sequence * const * >(val);
177                 sal_Int32 nElements = seq->nElements;
178 
179                 if (nElements > 0)
180                 {
181                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
182                     char const * pElements = seq->elements;
183                     for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
184                     {
185                         appendValue(
186                             buf, pElements + (nElementSize * nPos),
187                             elementTypeDescr->pWeakRef, false );
188                         if (nPos < (nElements - 1))
189                             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
190                     }
191                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
192                 }
193                 else
194                 {
195                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{}") );
196                 }
197                 TYPELIB_DANGER_RELEASE( elementTypeDescr );
198             }
199             TYPELIB_DANGER_RELEASE( typeDescr );
200         }
201         break;
202     }
203     case typelib_TypeClass_ANY: {
204         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
205         uno_Any const * pAny = static_cast< uno_Any const * >(val);
206         appendValue( buf, pAny->pData, pAny->pType, true );
207         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
208         break;
209     }
210     case typelib_TypeClass_TYPE:
211         buf.append( (*reinterpret_cast<
212                      typelib_TypeDescriptionReference * const * >(val)
213                         )->pTypeName );
214         break;
215     case typelib_TypeClass_STRING: {
216         buf.append( static_cast< sal_Unicode >('\"') );
217         rtl::OUString const & str = rtl::OUString::unacquired(
218             static_cast< rtl_uString * const * >(val) );
219         sal_Int32 len = str.getLength();
220         for ( sal_Int32 pos = 0; pos < len; ++pos )
221         {
222             sal_Unicode c = str[ pos ];
223             if (c == '\"')
224                 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\\"") );
225             else if (c == '\\')
226                 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\\\") );
227             else
228                 appendChar( buf, c );
229         }
230         buf.append( static_cast< sal_Unicode >('\"') );
231         break;
232     }
233     case typelib_TypeClass_ENUM: {
234         typelib_TypeDescription * typeDescr = 0;
235         typelib_typedescriptionreference_getDescription( &typeDescr, typeRef );
236         if (typeDescr == 0 || !typelib_typedescription_complete( &typeDescr )) {
237             appendTypeError( buf, typeRef );
238         }
239         else
240         {
241             sal_Int32 * pValues =
242                 reinterpret_cast< typelib_EnumTypeDescription * >(
243                     typeDescr )->pEnumValues;
244             sal_Int32 nPos = reinterpret_cast< typelib_EnumTypeDescription * >(
245                 typeDescr )->nEnumValues;
246             while (nPos--)
247             {
248                 if (pValues[ nPos ] == *static_cast< int const * >(val))
249                     break;
250             }
251             if (nPos >= 0)
252             {
253                 buf.append( reinterpret_cast< typelib_EnumTypeDescription * >(
254                                 typeDescr )->ppEnumNames[ nPos ] );
255             }
256             else
257             {
258                 buf.appendAscii(
259                     RTL_CONSTASCII_STRINGPARAM("?unknown enum value?") );
260             }
261         }
262         if (typeDescr != 0)
263             typelib_typedescription_release( typeDescr );
264         break;
265     }
266     case typelib_TypeClass_BOOLEAN:
267         if (*static_cast< sal_Bool const * >(val) != sal_False)
268             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("true") );
269         else
270             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("false") );
271         break;
272     case typelib_TypeClass_CHAR: {
273         buf.append( static_cast< sal_Unicode >('\'') );
274         sal_Unicode c = *static_cast< sal_Unicode const * >(val);
275         if (c == '\'')
276             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\\'") );
277         else if (c == '\\')
278             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\\\\") );
279         else
280             appendChar( buf, c );
281         buf.append( static_cast< sal_Unicode >('\'') );
282         break;
283     }
284     case typelib_TypeClass_FLOAT:
285         buf.append( *static_cast< float const * >(val) );
286         break;
287     case typelib_TypeClass_DOUBLE:
288         buf.append( *static_cast< double const * >(val) );
289         break;
290     case typelib_TypeClass_BYTE:
291         buf.append( static_cast< sal_Int32 >(
292                         *static_cast< sal_Int8 const * >(val) ) );
293         break;
294     case typelib_TypeClass_SHORT:
295         buf.append( static_cast< sal_Int32 >(
296                         *static_cast< sal_Int16 const * >(val) ) );
297         break;
298     case typelib_TypeClass_UNSIGNED_SHORT:
299         buf.append( static_cast< sal_Int32 >(
300                         *static_cast< sal_uInt16 const * >(val) ) );
301         break;
302     case typelib_TypeClass_LONG:
303         buf.append( *static_cast< sal_Int32 const * >(val) );
304         break;
305     case typelib_TypeClass_UNSIGNED_LONG:
306         buf.append( static_cast< sal_Int64 >(
307                         *static_cast< sal_uInt32 const * >(val) ) );
308         break;
309     case typelib_TypeClass_HYPER:
310     case typelib_TypeClass_UNSIGNED_HYPER:
311         buf.append( *static_cast< sal_Int64 const * >(val) );
312         break;
313 //     case typelib_TypeClass_UNION:
314 //     case typelib_TypeClass_ARRAY:
315 //     case typelib_TypeClass_UNKNOWN:
316 //     case typelib_TypeClass_SERVICE:
317 //     case typelib_TypeClass_MODULE:
318     default:
319         buf.append( static_cast< sal_Unicode >('?') );
320         break;
321     }
322 }
323 
324 } // anon namespace
325 
326 //==============================================================================
327 rtl::OUString anyToString( uno::Any const & value )
328 {
329     rtl::OUStringBuffer buf;
330     appendValue( buf, value.getValue(), value.getValueTypeRef(), true );
331     return buf.makeStringAndClear();
332 }
333 
334 } // namespace comphelper
335 
336