Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/misc/sequenceashashmap.cxx
Line
Count
Source
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
#include <sal/config.h>
21
22
#include <boost/property_tree/json_parser.hpp>
23
24
#include <com/sun/star/beans/NamedValue.hpp>
25
#include <com/sun/star/beans/PropertyValue.hpp>
26
#include <com/sun/star/lang/IllegalArgumentException.hpp>
27
#include <com/sun/star/reflection/XIdlField.hpp>
28
#include <com/sun/star/reflection/theCoreReflection.hpp>
29
#include <comphelper/JsonToPropertyValues_with_boost.hxx>
30
#include <comphelper/sequenceashashmap.hxx>
31
#include <comphelper/processfactory.hxx>
32
#include <comphelper/propertysequence.hxx>
33
#include <sal/log.hxx>
34
#include <o3tl/string_view.hxx>
35
#include <comphelper/sequence.hxx>
36
37
using namespace com::sun::star;
38
39
namespace
40
{
41
uno::Any jsonToUnoAny(const boost::property_tree::ptree& aTree)
42
0
{
43
0
    uno::Any aAny;
44
0
    uno::Any aValue;
45
0
    sal_Int32 nFields;
46
0
    uno::Reference<reflection::XIdlField> aField;
47
0
    boost::property_tree::ptree aNodeNull, aNodeValue, aNodeField;
48
0
    const std::string aType = aTree.get<std::string>("type", "");
49
0
    const std::string aValueStr = aTree.get<std::string>("value", "");
50
0
    uno::Sequence<uno::Reference<reflection::XIdlField>> aFields;
51
0
    uno::Reference<reflection::XIdlClass> xIdlClass
52
0
        = css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())
53
0
              ->forName(OUString::fromUtf8(aType));
54
0
    if (xIdlClass.is())
55
0
    {
56
0
        uno::TypeClass aTypeClass = xIdlClass->getTypeClass();
57
0
        xIdlClass->createObject(aAny);
58
0
        aFields = xIdlClass->getFields();
59
0
        nFields = aFields.getLength();
60
0
        aNodeValue = aTree.get_child("value", aNodeNull);
61
0
        if (nFields > 0 && aNodeValue != aNodeNull)
62
0
        {
63
0
            for (sal_Int32 itField = 0; itField < nFields; ++itField)
64
0
            {
65
0
                aField = aFields[itField];
66
0
                aNodeField = aNodeValue.get_child(aField->getName().toUtf8().getStr(), aNodeNull);
67
0
                if (aNodeField != aNodeNull)
68
0
                {
69
0
                    aValue = jsonToUnoAny(aNodeField);
70
0
                    aField->set(aAny, aValue);
71
0
                }
72
0
            }
73
0
        }
74
0
        else if (!aValueStr.empty())
75
0
        {
76
0
            if (aTypeClass == uno::TypeClass_VOID)
77
0
                aAny.clear();
78
0
            else if (aTypeClass == uno::TypeClass_BYTE)
79
0
                aAny <<= static_cast<sal_Int8>(o3tl::toInt32(aValueStr));
80
0
            else if (aTypeClass == uno::TypeClass_BOOLEAN)
81
0
                aAny <<= rtl_str_toBoolean(aValueStr.c_str());
82
0
            else if (aTypeClass == uno::TypeClass_SHORT)
83
0
                aAny <<= static_cast<sal_Int16>(o3tl::toInt32(aValueStr));
84
0
            else if (aTypeClass == uno::TypeClass_UNSIGNED_SHORT)
85
0
                aAny <<= static_cast<sal_uInt16>(o3tl::toUInt32(aValueStr));
86
0
            else if (aTypeClass == uno::TypeClass_LONG)
87
0
                aAny <<= o3tl::toInt32(aValueStr);
88
0
            else if (aTypeClass == uno::TypeClass_UNSIGNED_LONG)
89
0
                aAny <<= static_cast<sal_uInt32>(o3tl::toInt32(aValueStr));
90
0
            else if (aTypeClass == uno::TypeClass_FLOAT)
91
0
                aAny <<= rtl_str_toFloat(aValueStr.c_str());
92
0
            else if (aTypeClass == uno::TypeClass_DOUBLE)
93
0
                aAny <<= o3tl::toDouble(aValueStr);
94
0
            else if (aTypeClass == uno::TypeClass_STRING)
95
0
                aAny <<= OUString::fromUtf8(aValueStr);
96
0
        }
97
0
    }
98
0
    return aAny;
99
0
}
100
}
101
102
namespace comphelper{
103
104
SequenceAsHashMap::SequenceAsHashMap()
105
795k
{
106
795k
}
107
108
SequenceAsHashMap::SequenceAsHashMap(const css::uno::Any& aSource)
109
752k
{
110
752k
    (*this) << aSource;
111
752k
}
112
113
114
SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::uno::Any >& lSource)
115
8.48k
{
116
8.48k
    (*this) << lSource;
117
8.48k
}
118
119
SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
120
127k
{
121
127k
    (*this) << lSource;
122
127k
}
123
124
SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::NamedValue >& lSource)
125
6.62k
{
126
6.62k
    (*this) << lSource;
127
6.62k
}
128
129
void SequenceAsHashMap::operator<<(const css::uno::Any& aSource)
130
752k
{
131
    // An empty Any reset this instance!
132
752k
    if (!aSource.hasValue())
133
269
    {
134
269
        clear();
135
269
        return;
136
269
    }
137
138
752k
    css::uno::Sequence< css::beans::NamedValue > lN;
139
752k
    if (aSource >>= lN)
140
0
    {
141
0
        (*this) << lN;
142
0
        return;
143
0
    }
144
145
752k
    css::uno::Sequence< css::beans::PropertyValue > lP;
146
752k
    if (aSource >>= lP)
147
752k
    {
148
752k
        (*this) << lP;
149
752k
        return;
150
752k
    }
151
152
0
    throw css::lang::IllegalArgumentException(
153
0
        u"Any contains wrong type."_ustr, css::uno::Reference<css::uno::XInterface>(),
154
0
        -1);
155
752k
}
156
157
158
void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::uno::Any >& lSource)
159
8.48k
{
160
8.48k
    sal_Int32 c = lSource.getLength();
161
8.48k
    sal_Int32 i = 0;
162
163
8.48k
    m_aMap.reserve(c);
164
59.4k
    for (i=0; i<c; ++i)
165
50.9k
    {
166
50.9k
        css::beans::PropertyValue lP;
167
50.9k
        if (lSource[i] >>= lP)
168
0
        {
169
0
            if (
170
0
                (lP.Name.isEmpty()) ||
171
0
                (!lP.Value.hasValue())
172
0
               )
173
0
                throw css::lang::IllegalArgumentException(
174
0
                    u"PropertyValue struct contains no useful information."_ustr,
175
0
                    css::uno::Reference<css::uno::XInterface>(), -1);
176
0
            (*this)[lP.Name] = lP.Value;
177
0
            continue;
178
0
        }
179
180
50.9k
        css::beans::NamedValue lN;
181
50.9k
        if (lSource[i] >>= lN)
182
50.9k
        {
183
50.9k
            if (
184
50.9k
                (lN.Name.isEmpty()) ||
185
50.9k
                (!lN.Value.hasValue())
186
50.9k
               )
187
0
                throw css::lang::IllegalArgumentException(
188
0
                    u"NamedValue struct contains no useful information."_ustr,
189
0
                    css::uno::Reference<css::uno::XInterface>(), -1);
190
50.9k
            (*this)[lN.Name] = lN.Value;
191
50.9k
            continue;
192
50.9k
        }
193
194
        // ignore VOID Any ... but reject wrong filled ones!
195
0
        if (lSource[i].hasValue())
196
0
            throw css::lang::IllegalArgumentException(
197
0
                u"Any contains wrong type."_ustr,
198
0
                css::uno::Reference<css::uno::XInterface>(), -1);
199
0
    }
200
8.48k
}
201
202
void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
203
904k
{
204
904k
    clear();
205
206
904k
    m_aMap.reserve(lSource.getLength());
207
904k
    for (auto& rSource : lSource)
208
9.46M
        (*this)[rSource.Name] = rSource.Value;
209
904k
}
210
211
void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::NamedValue >& lSource)
212
6.62k
{
213
6.62k
    clear();
214
215
6.62k
    m_aMap.reserve(lSource.getLength());
216
6.62k
    for (auto& rSource : lSource)
217
7.52k
        (*this)[rSource.Name] = rSource.Value;
218
6.62k
}
219
220
void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::PropertyValue >& lDestination) const
221
370k
{
222
370k
    sal_Int32 c = static_cast<sal_Int32>(size());
223
370k
    lDestination.realloc(c);
224
370k
    css::beans::PropertyValue* pDestination = lDestination.getArray();
225
226
370k
    sal_Int32 i = 0;
227
370k
    for (const_iterator pThis  = begin();
228
3.34M
                        pThis != end()  ;
229
2.97M
                      ++pThis           )
230
2.97M
    {
231
2.97M
        pDestination[i].Name  = pThis->first.maString;
232
2.97M
        pDestination[i].Value = pThis->second;
233
2.97M
        ++i;
234
2.97M
    }
235
370k
}
236
237
void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::NamedValue >& lDestination) const
238
7.39k
{
239
7.39k
    sal_Int32 c = static_cast<sal_Int32>(size());
240
7.39k
    lDestination.realloc(c);
241
7.39k
    css::beans::NamedValue* pDestination = lDestination.getArray();
242
243
7.39k
    sal_Int32 i = 0;
244
7.39k
    for (const_iterator pThis  = begin();
245
53.2k
                        pThis != end()  ;
246
45.8k
                      ++pThis           )
247
45.8k
    {
248
45.8k
        pDestination[i].Name  = pThis->first.maString;
249
45.8k
        pDestination[i].Value = pThis->second;
250
45.8k
        ++i;
251
45.8k
    }
252
7.39k
}
253
254
css::uno::Any SequenceAsHashMap::getAsConstAny(bool bAsPropertyValueList) const
255
194k
{
256
194k
    css::uno::Any aDestination;
257
194k
    if (bAsPropertyValueList)
258
194k
        aDestination <<= getAsConstPropertyValueList();
259
27
    else
260
27
        aDestination <<= getAsConstNamedValueList();
261
194k
    return aDestination;
262
194k
}
263
264
css::uno::Sequence< css::beans::NamedValue > SequenceAsHashMap::getAsConstNamedValueList() const
265
7.05k
{
266
7.05k
    css::uno::Sequence< css::beans::NamedValue > lReturn;
267
7.05k
    (*this) >> lReturn;
268
7.05k
    return lReturn;
269
7.05k
}
270
271
css::uno::Sequence< css::beans::PropertyValue > SequenceAsHashMap::getAsConstPropertyValueList() const
272
370k
{
273
370k
    css::uno::Sequence< css::beans::PropertyValue > lReturn;
274
370k
    (*this) >> lReturn;
275
370k
    return lReturn;
276
370k
}
277
278
bool SequenceAsHashMap::match(const SequenceAsHashMap& rCheck) const
279
0
{
280
0
    for (auto const& elem : rCheck)
281
0
    {
282
0
        const OUString& sCheckName  = elem.first.maString;
283
0
        const css::uno::Any&   aCheckValue = elem.second;
284
0
        const_iterator         pFound      = find(sCheckName);
285
286
0
        if (pFound == end())
287
0
            return false;
288
289
0
        const css::uno::Any& aFoundValue = pFound->second;
290
0
        if (aFoundValue != aCheckValue)
291
0
            return false;
292
0
    }
293
294
0
    return true;
295
0
}
296
297
void SequenceAsHashMap::update(const SequenceAsHashMap& rUpdate)
298
25.5k
{
299
25.5k
    m_aMap.reserve(std::max(size(), rUpdate.size()));
300
25.5k
    for (auto const& elem : rUpdate.m_aMap)
301
81.6k
    {
302
81.6k
        m_aMap[elem.first] = elem.second;
303
81.6k
    }
304
25.5k
}
305
306
std::vector<css::beans::PropertyValue> JsonToPropertyValues(const boost::property_tree::ptree& aTree)
307
75
{
308
75
    std::vector<beans::PropertyValue> aArguments;
309
75
    boost::property_tree::ptree aNodeNull, aNodeValue;
310
75
    for (const auto& rPair : aTree)
311
75
    {
312
75
        const std::string aType = rPair.second.get<std::string>("type", "");
313
75
        const std::string aValueStr = rPair.second.get<std::string>("value", "");
314
315
75
        beans::PropertyValue aValue;
316
75
        aValue.Name = OUString::fromUtf8(rPair.first);
317
75
        if (aType == "string")
318
0
            aValue.Value <<= OUString::fromUtf8(aValueStr);
319
75
        else if (aType == "boolean")
320
75
            aValue.Value <<= rtl_str_toBoolean(aValueStr.c_str());
321
0
        else if (aType == "float")
322
0
            aValue.Value <<= rtl_str_toFloat(aValueStr.c_str());
323
0
        else if (aType == "long")
324
0
            aValue.Value <<= o3tl::toInt32(aValueStr);
325
0
        else if (aType == "short")
326
0
            aValue.Value <<= sal_Int16(o3tl::toInt32(aValueStr));
327
0
        else if (aType == "unsigned short")
328
0
            aValue.Value <<= sal_uInt16(o3tl::toUInt32(aValueStr));
329
0
        else if (aType == "int64")
330
0
            aValue.Value <<= o3tl::toInt64(aValueStr);
331
0
        else if (aType == "int32")
332
0
            aValue.Value <<= o3tl::toInt32(aValueStr);
333
0
        else if (aType == "int16")
334
0
            aValue.Value <<= sal_Int16(o3tl::toInt32(aValueStr));
335
0
        else if (aType == "uint64")
336
0
            aValue.Value <<= rtl_str_toUInt64(aValueStr.c_str(), 10);
337
0
        else if (aType == "uint32")
338
0
            aValue.Value <<= o3tl::toUInt32(aValueStr);
339
0
        else if (aType == "uint16")
340
0
            aValue.Value <<= sal_uInt16(o3tl::toUInt32(aValueStr));
341
0
        else if (aType == "[]byte")
342
0
        {
343
0
            aNodeValue = rPair.second.get_child("value", aNodeNull);
344
0
            if (aNodeValue != aNodeNull && aNodeValue.size() == 0)
345
0
            {
346
0
                uno::Sequence<sal_Int8> aSeqByte(reinterpret_cast<const sal_Int8*>(aValueStr.c_str()),
347
0
                                                 aValueStr.size());
348
0
                aValue.Value <<= aSeqByte;
349
0
            }
350
0
        }
351
0
        else if (aType == "any")
352
0
        {
353
0
            aNodeValue = rPair.second.get_child("value", aNodeNull);
354
0
            if (aNodeValue != aNodeNull && !aNodeValue.empty())
355
0
            {
356
0
                aValue.Value = jsonToUnoAny(aNodeValue);
357
0
            }
358
0
        }
359
0
        else if (aType == "[]any")
360
0
        {
361
0
            aNodeValue = rPair.second.get_child("value", aNodeNull);
362
0
            if (aNodeValue != aNodeNull && !aNodeValue.empty())
363
0
            {
364
0
                uno::Sequence<uno::Any> aSeq(aNodeValue.size());
365
0
                std::transform(aNodeValue.begin(), aNodeValue.end(), aSeq.getArray(),
366
0
                               [](const auto& rSeqPair) { return jsonToUnoAny(rSeqPair.second); });
367
0
                aValue.Value <<= aSeq;
368
0
            }
369
0
        }
370
0
        else if (aType == "[]com.sun.star.beans.PropertyValue")
371
0
        {
372
0
            aNodeValue = rPair.second.get_child("value", aNodeNull);
373
0
            aValue.Value <<= comphelper::containerToSequence(JsonToPropertyValues(aNodeValue));
374
0
        }
375
0
        else if (aType == "[][]com.sun.star.beans.PropertyValue")
376
0
        {
377
0
            aNodeValue = rPair.second.get_child("value", aNodeNull);
378
0
            std::vector<uno::Sequence<beans::PropertyValue>> aSeqs;
379
0
            for (const auto& rItem : aNodeValue)
380
0
            {
381
0
                aSeqs.push_back(comphelper::containerToSequence(JsonToPropertyValues(rItem.second)));
382
0
            }
383
0
            aValue.Value <<= comphelper::containerToSequence(aSeqs);
384
0
        }
385
0
        else
386
0
            SAL_WARN("comphelper", "JsonToPropertyValues: unhandled type '" << aType << "'");
387
75
        aArguments.push_back(aValue);
388
75
    }
389
75
    return aArguments;
390
75
}
391
392
std::vector<css::beans::PropertyValue> JsonToPropertyValues(std::string_view rJson)
393
75
{
394
75
    boost::property_tree::ptree aTree;
395
75
    std::stringstream aStream((std::string(rJson)));
396
75
    boost::property_tree::read_json(aStream, aTree);
397
75
    return JsonToPropertyValues(aTree);
398
75
}
399
400
} // namespace comphelper
401
402
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */