Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/comphelper/source/misc/anytostring.cxx
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
21
#include <comphelper/anytostring.hxx>
22
#include <rtl/ustrbuf.hxx>
23
#include <typelib/typedescription.hxx>
24
#include <com/sun/star/lang/XServiceInfo.hpp>
25
26
#include "typedescriptionref.hxx"
27
28
using namespace ::com::sun::star;
29
using ::com::sun::star::uno::TypeDescription;
30
using ::comphelper::detail::TypeDescriptionRef;
31
32
namespace comphelper {
33
namespace {
34
35
void appendTypeError(
36
    OUStringBuffer & buf, const typelib_TypeDescriptionReference * typeRef )
37
0
{
38
0
    buf.append( "<cannot get type description of type " );
39
0
    buf.append( OUString::unacquired( &typeRef->pTypeName ) );
40
0
    buf.append( '>' );
41
0
}
42
43
void appendChar( OUStringBuffer & buf, sal_Unicode c )
44
0
{
45
0
    if (c < ' ' || c > '~') {
46
0
        buf.append( "\\X" );
47
0
        OUString const s(
48
0
            OUString::number( static_cast< sal_Int32 >(c), 16 ) );
49
0
        for ( sal_Int32 f = 4 - s.getLength(); f > 0; --f )
50
0
            buf.append( '0' );
51
0
        buf.append( s );
52
0
    }
53
0
    else {
54
0
        buf.append( c );
55
0
    }
56
0
}
57
58
59
void appendValue( OUStringBuffer & buf,
60
                  void const * val, typelib_TypeDescriptionReference * typeRef,
61
                  bool prependType )
62
0
{
63
0
    if (typeRef->eTypeClass == typelib_TypeClass_VOID) {
64
0
        buf.append( "void" );
65
0
        return;
66
0
    }
67
0
    assert(val != nullptr);
68
69
0
    if (prependType &&
70
0
        typeRef->eTypeClass != typelib_TypeClass_STRING &&
71
0
        typeRef->eTypeClass != typelib_TypeClass_CHAR &&
72
0
        typeRef->eTypeClass != typelib_TypeClass_BOOLEAN)
73
0
    {
74
0
        buf.append( '(' );
75
0
        buf.append( OUString::unacquired( &typeRef->pTypeName ) );
76
0
        buf.append( ") " );
77
0
    }
78
79
0
    switch (typeRef->eTypeClass) {
80
0
    case typelib_TypeClass_INTERFACE: {
81
0
        buf.append( '@' );
82
0
        buf.append( reinterpret_cast< sal_Int64 >(
83
0
                        *static_cast< void * const * >(val) ), 16 );
84
0
        uno::Reference< lang::XServiceInfo > xServiceInfo(
85
0
            *static_cast< uno::XInterface * const * >(val),
86
0
            uno::UNO_QUERY );
87
0
        if (xServiceInfo.is()) {
88
0
            buf.append( " (ImplementationName = \"" );
89
0
            buf.append( xServiceInfo->getImplementationName() );
90
0
            buf.append( "\")" );
91
0
        }
92
0
        break;
93
0
    }
94
0
    case typelib_TypeClass_STRUCT:
95
0
    case typelib_TypeClass_EXCEPTION: {
96
0
        buf.append( "{ " );
97
0
        TypeDescription typeDescr( typeRef );
98
0
        if (!typeDescr.is())
99
0
            typeDescr.makeComplete();
100
0
        if (!typeDescr.is()) {
101
0
            appendTypeError( buf, typeRef );
102
0
        }
103
0
        else {
104
0
            typelib_CompoundTypeDescription * compType =
105
0
                reinterpret_cast< typelib_CompoundTypeDescription * >(
106
0
                    typeDescr.get() );
107
0
            sal_Int32 nDescr = compType->nMembers;
108
109
0
            if (compType->pBaseTypeDescription) {
110
0
                appendValue(
111
0
                    buf, val, reinterpret_cast<
112
0
                    typelib_TypeDescription * >(
113
0
                        compType->pBaseTypeDescription)->pWeakRef, false );
114
0
                if (nDescr > 0)
115
0
                    buf.append( ", " );
116
0
            }
117
118
0
            typelib_TypeDescriptionReference ** ppTypeRefs =
119
0
                compType->ppTypeRefs;
120
0
            sal_Int32 * memberOffsets = compType->pMemberOffsets;
121
0
            rtl_uString ** ppMemberNames = compType->ppMemberNames;
122
123
0
            for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos )
124
0
            {
125
0
                buf.append( ppMemberNames[ nPos ] );
126
0
                buf.append( " = " );
127
0
                TypeDescriptionRef memberType( ppTypeRefs[ nPos ] );
128
0
                if (!memberType.is()) {
129
0
                    appendTypeError( buf, ppTypeRefs[ nPos ] );
130
0
                }
131
0
                else {
132
0
                    appendValue( buf,
133
0
                                 static_cast< char const * >(
134
0
                                     val ) + memberOffsets[ nPos ],
135
0
                                 memberType->pWeakRef, true );
136
0
                }
137
0
                if (nPos < (nDescr - 1))
138
0
                    buf.append( ", " );
139
0
            }
140
0
        }
141
0
        buf.append( " }" );
142
0
        break;
143
0
    }
144
0
    case typelib_TypeClass_SEQUENCE: {
145
0
        TypeDescriptionRef typeDescr( typeRef );
146
0
        if (!typeDescr.is()) {
147
0
            appendTypeError( buf,typeRef );
148
0
        }
149
0
        else {
150
0
            typelib_TypeDescriptionReference * elementTypeRef =
151
0
                reinterpret_cast<
152
0
                typelib_IndirectTypeDescription * >(typeDescr.get())->pType;
153
0
            TypeDescriptionRef elementTypeDescr( elementTypeRef );
154
0
            if (!elementTypeDescr.is())
155
0
            {
156
0
                appendTypeError( buf, elementTypeRef );
157
0
            }
158
0
            else
159
0
            {
160
0
                sal_Int32 nElementSize = elementTypeDescr->nSize;
161
0
                uno_Sequence * seq =
162
0
                    *static_cast< uno_Sequence * const * >(val);
163
0
                sal_Int32 nElements = seq->nElements;
164
165
0
                if (nElements > 0)
166
0
                {
167
0
                    buf.append( "{ " );
168
0
                    char const * pElements = seq->elements;
169
0
                    for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
170
0
                    {
171
0
                        appendValue(
172
0
                            buf, pElements + (nElementSize * nPos),
173
0
                            elementTypeDescr->pWeakRef, false );
174
0
                        if (nPos < (nElements - 1))
175
0
                            buf.append( ", " );
176
0
                    }
177
0
                    buf.append( " }" );
178
0
                }
179
0
                else
180
0
                {
181
0
                    buf.append( "{}" );
182
0
                }
183
0
            }
184
0
        }
185
0
        break;
186
0
    }
187
0
    case typelib_TypeClass_ANY: {
188
0
        buf.append( "{ " );
189
0
        uno_Any const * pAny = static_cast< uno_Any const * >(val);
190
0
        appendValue( buf, pAny->pData, pAny->pType, true );
191
0
        buf.append( " }" );
192
0
        break;
193
0
    }
194
0
    case typelib_TypeClass_TYPE:
195
0
        buf.append( (*static_cast<
196
0
                     typelib_TypeDescriptionReference * const * >(val)
197
0
                        )->pTypeName );
198
0
        break;
199
0
    case typelib_TypeClass_STRING: {
200
0
        buf.append( '\"' );
201
0
        OUString const & str = OUString::unacquired(
202
0
            static_cast< rtl_uString * const * >(val) );
203
0
        sal_Int32 len = str.getLength();
204
0
        for ( sal_Int32 pos = 0; pos < len; ++pos )
205
0
        {
206
0
            sal_Unicode c = str[ pos ];
207
0
            if (c == '\"')
208
0
                buf.append( "\\\"" );
209
0
            else if (c == '\\')
210
0
                buf.append( "\\\\" );
211
0
            else
212
0
                appendChar( buf, c );
213
0
        }
214
0
        buf.append( '\"' );
215
0
        break;
216
0
    }
217
0
    case typelib_TypeClass_ENUM: {
218
0
        TypeDescription typeDescr( typeRef );
219
0
        if (!typeDescr.is())
220
0
            typeDescr.makeComplete();
221
0
        if (!typeDescr.is()) {
222
0
            appendTypeError( buf, typeRef );
223
0
        }
224
0
        else
225
0
        {
226
0
            sal_Int32 * pValues =
227
0
                reinterpret_cast< typelib_EnumTypeDescription * >(
228
0
                    typeDescr.get() )->pEnumValues;
229
0
            sal_Int32 nPos = reinterpret_cast< typelib_EnumTypeDescription * >(
230
0
                typeDescr.get() )->nEnumValues;
231
0
            while (nPos--)
232
0
            {
233
0
                if (pValues[ nPos ] == *static_cast< int const * >(val))
234
0
                    break;
235
0
            }
236
0
            if (nPos >= 0)
237
0
            {
238
0
                buf.append( reinterpret_cast< typelib_EnumTypeDescription * >(
239
0
                                typeDescr.get() )->ppEnumNames[ nPos ] );
240
0
            }
241
0
            else
242
0
            {
243
0
                buf.append( "?unknown enum value?" );
244
0
            }
245
0
        }
246
0
        break;
247
0
    }
248
0
    case typelib_TypeClass_BOOLEAN:
249
0
        if (*static_cast< sal_Bool const * >(val))
250
0
            buf.append( "true" );
251
0
        else
252
0
            buf.append( "false" );
253
0
        break;
254
0
    case typelib_TypeClass_CHAR: {
255
0
        buf.append( '\'' );
256
0
        sal_Unicode c = *static_cast< sal_Unicode const * >(val);
257
0
        if (c == '\'')
258
0
            buf.append( "\\\'" );
259
0
        else if (c == '\\')
260
0
            buf.append( "\\\\" );
261
0
        else
262
0
            appendChar( buf, c );
263
0
        buf.append( '\'' );
264
0
        break;
265
0
    }
266
0
    case typelib_TypeClass_FLOAT:
267
0
        buf.append( *static_cast< float const * >(val) );
268
0
        break;
269
0
    case typelib_TypeClass_DOUBLE:
270
0
        buf.append( *static_cast< double const * >(val) );
271
0
        break;
272
0
    case typelib_TypeClass_BYTE:
273
0
        buf.append( static_cast< sal_Int32 >(
274
0
                        *static_cast< sal_Int8 const * >(val) ) );
275
0
        break;
276
0
    case typelib_TypeClass_SHORT:
277
0
        buf.append( static_cast< sal_Int32 >(
278
0
                        *static_cast< sal_Int16 const * >(val) ) );
279
0
        break;
280
0
    case typelib_TypeClass_UNSIGNED_SHORT:
281
0
        buf.append( static_cast< sal_Int32 >(
282
0
                        *static_cast< sal_uInt16 const * >(val) ) );
283
0
        break;
284
0
    case typelib_TypeClass_LONG:
285
0
        buf.append( *static_cast< sal_Int32 const * >(val) );
286
0
        break;
287
0
    case typelib_TypeClass_UNSIGNED_LONG:
288
0
        buf.append( static_cast< sal_Int64 >(
289
0
                        *static_cast< sal_uInt32 const * >(val) ) );
290
0
        break;
291
0
    case typelib_TypeClass_HYPER:
292
0
    case typelib_TypeClass_UNSIGNED_HYPER:
293
0
        buf.append( *static_cast< sal_Int64 const * >(val) );
294
0
        break;
295
//     case typelib_TypeClass_UNKNOWN:
296
//     case typelib_TypeClass_SERVICE:
297
//     case typelib_TypeClass_MODULE:
298
0
    default:
299
0
        buf.append( '?' );
300
0
        break;
301
0
    }
302
0
}
303
304
} // anon namespace
305
306
307
OUString anyToString( uno::Any const & value )
308
0
{
309
0
    OUStringBuffer buf;
310
0
    appendValue( buf, value.getValue(), value.getValueTypeRef(), true );
311
0
    return buf.makeStringAndClear();
312
0
}
313
314
} // namespace comphelper
315
316
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */