Coverage Report

Created: 2026-03-31 11:00

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
1.12M
{
106
1.12M
}
107
108
SequenceAsHashMap::SequenceAsHashMap(const css::uno::Any& aSource)
109
827k
{
110
827k
    (*this) << aSource;
111
827k
}
112
113
114
SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::uno::Any >& lSource)
115
8.17k
{
116
8.17k
    (*this) << lSource;
117
8.17k
}
118
119
SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
120
223k
{
121
223k
    (*this) << lSource;
122
223k
}
123
124
SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::NamedValue >& lSource)
125
6.78k
{
126
6.78k
    (*this) << lSource;
127
6.78k
}
128
129
void SequenceAsHashMap::operator<<(const css::uno::Any& aSource)
130
827k
{
131
    // An empty Any reset this instance!
132
827k
    if (!aSource.hasValue())
133
249
    {
134
249
        clear();
135
249
        return;
136
249
    }
137
138
827k
    css::uno::Sequence< css::beans::NamedValue > lN;
139
827k
    if (aSource >>= lN)
140
0
    {
141
0
        (*this) << lN;
142
0
        return;
143
0
    }
144
145
827k
    css::uno::Sequence< css::beans::PropertyValue > lP;
146
827k
    if (aSource >>= lP)
147
827k
    {
148
827k
        (*this) << lP;
149
827k
        return;
150
827k
    }
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
827k
}
156
157
158
void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::uno::Any >& lSource)
159
8.17k
{
160
8.17k
    sal_Int32 c = lSource.getLength();
161
8.17k
    sal_Int32 i = 0;
162
163
8.17k
    m_aMap.reserve(c);
164
57.2k
    for (i=0; i<c; ++i)
165
49.0k
    {
166
49.0k
        css::beans::PropertyValue lP;
167
49.0k
        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
49.0k
        css::beans::NamedValue lN;
181
49.0k
        if (lSource[i] >>= lN)
182
49.0k
        {
183
49.0k
            if (
184
49.0k
                (lN.Name.isEmpty()) ||
185
49.0k
                (!lN.Value.hasValue())
186
49.0k
               )
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
49.0k
            (*this)[lN.Name] = lN.Value;
191
49.0k
            continue;
192
49.0k
        }
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.17k
}
201
202
void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
203
1.09M
{
204
1.09M
    clear();
205
206
1.09M
    m_aMap.reserve(lSource.getLength());
207
1.09M
    for (auto& rSource : lSource)
208
10.4M
        (*this)[rSource.Name] = rSource.Value;
209
1.09M
}
210
211
void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::NamedValue >& lSource)
212
6.78k
{
213
6.78k
    clear();
214
215
6.78k
    m_aMap.reserve(lSource.getLength());
216
6.78k
    for (auto& rSource : lSource)
217
9.09k
        (*this)[rSource.Name] = rSource.Value;
218
6.78k
}
219
220
void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::PropertyValue >& lDestination) const
221
498k
{
222
498k
    sal_Int32 c = static_cast<sal_Int32>(size());
223
498k
    lDestination.realloc(c);
224
498k
    css::beans::PropertyValue* pDestination = lDestination.getArray();
225
226
498k
    sal_Int32 i = 0;
227
498k
    for (const_iterator pThis  = begin();
228
4.01M
                        pThis != end()  ;
229
3.51M
                      ++pThis           )
230
3.51M
    {
231
3.51M
        pDestination[i].Name  = pThis->first.maString;
232
3.51M
        pDestination[i].Value = pThis->second;
233
3.51M
        ++i;
234
3.51M
    }
235
498k
}
236
237
void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::NamedValue >& lDestination) const
238
8.39k
{
239
8.39k
    sal_Int32 c = static_cast<sal_Int32>(size());
240
8.39k
    lDestination.realloc(c);
241
8.39k
    css::beans::NamedValue* pDestination = lDestination.getArray();
242
243
8.39k
    sal_Int32 i = 0;
244
8.39k
    for (const_iterator pThis  = begin();
245
53.7k
                        pThis != end()  ;
246
45.3k
                      ++pThis           )
247
45.3k
    {
248
45.3k
        pDestination[i].Name  = pThis->first.maString;
249
45.3k
        pDestination[i].Value = pThis->second;
250
45.3k
        ++i;
251
45.3k
    }
252
8.39k
}
253
254
css::uno::Any SequenceAsHashMap::getAsConstAny(bool bAsPropertyValueList) const
255
220k
{
256
220k
    css::uno::Any aDestination;
257
220k
    if (bAsPropertyValueList)
258
220k
        aDestination <<= getAsConstPropertyValueList();
259
23
    else
260
23
        aDestination <<= getAsConstNamedValueList();
261
220k
    return aDestination;
262
220k
}
263
264
css::uno::Sequence< css::beans::NamedValue > SequenceAsHashMap::getAsConstNamedValueList() const
265
7.64k
{
266
7.64k
    css::uno::Sequence< css::beans::NamedValue > lReturn;
267
7.64k
    (*this) >> lReturn;
268
7.64k
    return lReturn;
269
7.64k
}
270
271
css::uno::Sequence< css::beans::PropertyValue > SequenceAsHashMap::getAsConstPropertyValueList() const
272
498k
{
273
498k
    css::uno::Sequence< css::beans::PropertyValue > lReturn;
274
498k
    (*this) >> lReturn;
275
498k
    return lReturn;
276
498k
}
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
26.1k
{
299
26.1k
    m_aMap.reserve(std::max(size(), rUpdate.size()));
300
26.1k
    for (auto const& elem : rUpdate.m_aMap)
301
81.8k
    {
302
81.8k
        m_aMap[elem.first] = elem.second;
303
81.8k
    }
304
26.1k
}
305
306
std::vector<css::beans::PropertyValue> JsonToPropertyValues(const boost::property_tree::ptree& aTree)
307
8
{
308
8
    std::vector<beans::PropertyValue> aArguments;
309
8
    boost::property_tree::ptree aNodeNull, aNodeValue;
310
8
    for (const auto& rPair : aTree)
311
8
    {
312
8
        const std::string aType = rPair.second.get<std::string>("type", "");
313
8
        const std::string aValueStr = rPair.second.get<std::string>("value", "");
314
315
8
        beans::PropertyValue aValue;
316
8
        aValue.Name = OUString::fromUtf8(rPair.first);
317
8
        if (aType == "string")
318
0
            aValue.Value <<= OUString::fromUtf8(aValueStr);
319
8
        else if (aType == "boolean")
320
8
            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
8
        aArguments.push_back(aValue);
388
8
    }
389
8
    return aArguments;
390
8
}
391
392
std::vector<css::beans::PropertyValue> JsonToPropertyValues(std::string_view rJson)
393
8
{
394
8
    boost::property_tree::ptree aTree;
395
8
    std::stringstream aStream((std::string(rJson)));
396
8
    boost::property_tree::read_json(aStream, aTree);
397
8
    return JsonToPropertyValues(aTree);
398
8
}
399
400
} // namespace comphelper
401
402
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */