1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <boost/property_tree/json_parser.hpp>
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/sequenceashashmap.hxx>
30 #include <comphelper/processfactory.hxx>
31 #include <comphelper/propertysequence.hxx>
32 #include <sal/log.hxx>
33 #include <o3tl/string_view.hxx>
34 #include <comphelper/sequence.hxx>
36 using namespace com::sun::star
;
40 uno::Any
jsonToUnoAny(const boost::property_tree::ptree
& aTree
)
45 uno::Reference
<reflection::XIdlField
> aField
;
46 boost::property_tree::ptree aNodeNull
, aNodeValue
, aNodeField
;
47 const std::string
& rType
= aTree
.get
<std::string
>("type", "");
48 const std::string
& rValue
= aTree
.get
<std::string
>("value", "");
49 uno::Sequence
<uno::Reference
<reflection::XIdlField
>> aFields
;
50 uno::Reference
<reflection::XIdlClass
> xIdlClass
51 = css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())
52 ->forName(OUString::fromUtf8(rType
));
55 uno::TypeClass aTypeClass
= xIdlClass
->getTypeClass();
56 xIdlClass
->createObject(aAny
);
57 aFields
= xIdlClass
->getFields();
58 nFields
= aFields
.getLength();
59 aNodeValue
= aTree
.get_child("value", aNodeNull
);
60 if (nFields
> 0 && aNodeValue
!= aNodeNull
)
62 for (sal_Int32 itField
= 0; itField
< nFields
; ++itField
)
64 aField
= aFields
[itField
];
65 aNodeField
= aNodeValue
.get_child(aField
->getName().toUtf8().getStr(), aNodeNull
);
66 if (aNodeField
!= aNodeNull
)
68 aValue
= jsonToUnoAny(aNodeField
);
69 aField
->set(aAny
, aValue
);
73 else if (!rValue
.empty())
75 if (aTypeClass
== uno::TypeClass_VOID
)
77 else if (aTypeClass
== uno::TypeClass_BYTE
)
78 aAny
<<= static_cast<sal_Int8
>(o3tl::toInt32(rValue
));
79 else if (aTypeClass
== uno::TypeClass_BOOLEAN
)
80 aAny
<<= OString(rValue
).toBoolean();
81 else if (aTypeClass
== uno::TypeClass_SHORT
)
82 aAny
<<= static_cast<sal_Int16
>(o3tl::toInt32(rValue
));
83 else if (aTypeClass
== uno::TypeClass_UNSIGNED_SHORT
)
84 aAny
<<= static_cast<sal_uInt16
>(o3tl::toUInt32(rValue
));
85 else if (aTypeClass
== uno::TypeClass_LONG
)
86 aAny
<<= o3tl::toInt32(rValue
);
87 else if (aTypeClass
== uno::TypeClass_UNSIGNED_LONG
)
88 aAny
<<= static_cast<sal_uInt32
>(o3tl::toInt32(rValue
));
89 else if (aTypeClass
== uno::TypeClass_FLOAT
)
90 aAny
<<= OString(rValue
).toFloat();
91 else if (aTypeClass
== uno::TypeClass_DOUBLE
)
92 aAny
<<= o3tl::toDouble(rValue
);
93 else if (aTypeClass
== uno::TypeClass_STRING
)
94 aAny
<<= OUString::fromUtf8(rValue
);
101 namespace comphelper
{
103 SequenceAsHashMap::SequenceAsHashMap()
107 SequenceAsHashMap::SequenceAsHashMap(const css::uno::Any
& aSource
)
113 SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence
< css::uno::Any
>& lSource
)
118 SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence
< css::beans::PropertyValue
>& lSource
)
123 SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence
< css::beans::NamedValue
>& lSource
)
128 void SequenceAsHashMap::operator<<(const css::uno::Any
& aSource
)
130 // An empty Any reset this instance!
131 if (!aSource
.hasValue())
137 css::uno::Sequence
< css::beans::NamedValue
> lN
;
144 css::uno::Sequence
< css::beans::PropertyValue
> lP
;
151 throw css::lang::IllegalArgumentException(
152 "Any contains wrong type.", css::uno::Reference
<css::uno::XInterface
>(),
157 void SequenceAsHashMap::operator<<(const css::uno::Sequence
< css::uno::Any
>& lSource
)
159 sal_Int32 c
= lSource
.getLength();
165 css::beans::PropertyValue lP
;
166 if (lSource
[i
] >>= lP
)
169 (lP
.Name
.isEmpty()) ||
170 (!lP
.Value
.hasValue())
172 throw css::lang::IllegalArgumentException(
173 "PropertyValue struct contains no useful information.",
174 css::uno::Reference
<css::uno::XInterface
>(), -1);
175 (*this)[lP
.Name
] = lP
.Value
;
179 css::beans::NamedValue lN
;
180 if (lSource
[i
] >>= lN
)
183 (lN
.Name
.isEmpty()) ||
184 (!lN
.Value
.hasValue())
186 throw css::lang::IllegalArgumentException(
187 "NamedValue struct contains no useful information.",
188 css::uno::Reference
<css::uno::XInterface
>(), -1);
189 (*this)[lN
.Name
] = lN
.Value
;
193 // ignore VOID Any ... but reject wrong filled ones!
194 if (lSource
[i
].hasValue())
195 throw css::lang::IllegalArgumentException(
196 "Any contains wrong type.",
197 css::uno::Reference
<css::uno::XInterface
>(), -1);
201 void SequenceAsHashMap::operator<<(const css::uno::Sequence
< css::beans::PropertyValue
>& lSource
)
205 sal_Int32 c
= lSource
.getLength();
206 const css::beans::PropertyValue
* pSource
= lSource
.getConstArray();
209 for (sal_Int32 i
=0; i
<c
; ++i
)
210 (*this)[pSource
[i
].Name
] = pSource
[i
].Value
;
213 void SequenceAsHashMap::operator<<(const css::uno::Sequence
< css::beans::NamedValue
>& lSource
)
217 sal_Int32 c
= lSource
.getLength();
218 const css::beans::NamedValue
* pSource
= lSource
.getConstArray();
221 for (sal_Int32 i
=0; i
<c
; ++i
)
222 (*this)[pSource
[i
].Name
] = pSource
[i
].Value
;
225 void SequenceAsHashMap::operator>>(css::uno::Sequence
< css::beans::PropertyValue
>& lDestination
) const
227 sal_Int32 c
= static_cast<sal_Int32
>(size());
228 lDestination
.realloc(c
);
229 css::beans::PropertyValue
* pDestination
= lDestination
.getArray();
232 for (const_iterator pThis
= begin();
236 pDestination
[i
].Name
= pThis
->first
.maString
;
237 pDestination
[i
].Value
= pThis
->second
;
242 void SequenceAsHashMap::operator>>(css::uno::Sequence
< css::beans::NamedValue
>& lDestination
) const
244 sal_Int32 c
= static_cast<sal_Int32
>(size());
245 lDestination
.realloc(c
);
246 css::beans::NamedValue
* pDestination
= lDestination
.getArray();
249 for (const_iterator pThis
= begin();
253 pDestination
[i
].Name
= pThis
->first
.maString
;
254 pDestination
[i
].Value
= pThis
->second
;
259 css::uno::Any
SequenceAsHashMap::getAsConstAny(bool bAsPropertyValueList
) const
261 css::uno::Any aDestination
;
262 if (bAsPropertyValueList
)
263 aDestination
<<= getAsConstPropertyValueList();
265 aDestination
<<= getAsConstNamedValueList();
269 css::uno::Sequence
< css::beans::NamedValue
> SequenceAsHashMap::getAsConstNamedValueList() const
271 css::uno::Sequence
< css::beans::NamedValue
> lReturn
;
276 css::uno::Sequence
< css::beans::PropertyValue
> SequenceAsHashMap::getAsConstPropertyValueList() const
278 css::uno::Sequence
< css::beans::PropertyValue
> lReturn
;
283 bool SequenceAsHashMap::match(const SequenceAsHashMap
& rCheck
) const
285 for (auto const& elem
: rCheck
)
287 const OUString
& sCheckName
= elem
.first
.maString
;
288 const css::uno::Any
& aCheckValue
= elem
.second
;
289 const_iterator pFound
= find(sCheckName
);
294 const css::uno::Any
& aFoundValue
= pFound
->second
;
295 if (aFoundValue
!= aCheckValue
)
302 void SequenceAsHashMap::update(const SequenceAsHashMap
& rUpdate
)
304 m_aMap
.reserve(std::max(size(), rUpdate
.size()));
305 for (auto const& elem
: rUpdate
.m_aMap
)
307 m_aMap
[elem
.first
] = elem
.second
;
311 std::vector
<css::beans::PropertyValue
> JsonToPropertyValues(const OString
& rJson
)
313 std::vector
<beans::PropertyValue
> aArguments
;
314 boost::property_tree::ptree aTree
, aNodeNull
, aNodeValue
;
315 std::stringstream
aStream((std::string(rJson
)));
316 boost::property_tree::read_json(aStream
, aTree
);
318 for (const auto& rPair
: aTree
)
320 const std::string
& rType
= rPair
.second
.get
<std::string
>("type", "");
321 const std::string
& rValue
= rPair
.second
.get
<std::string
>("value", "");
323 beans::PropertyValue aValue
;
324 aValue
.Name
= OUString::fromUtf8(rPair
.first
);
325 if (rType
== "string")
326 aValue
.Value
<<= OUString::fromUtf8(rValue
);
327 else if (rType
== "boolean")
328 aValue
.Value
<<= OString(rValue
).toBoolean();
329 else if (rType
== "float")
330 aValue
.Value
<<= OString(rValue
).toFloat();
331 else if (rType
== "long")
332 aValue
.Value
<<= o3tl::toInt32(rValue
);
333 else if (rType
== "short")
334 aValue
.Value
<<= sal_Int16(o3tl::toInt32(rValue
));
335 else if (rType
== "unsigned short")
336 aValue
.Value
<<= sal_uInt16(o3tl::toUInt32(rValue
));
337 else if (rType
== "int64")
338 aValue
.Value
<<= o3tl::toInt64(rValue
);
339 else if (rType
== "int32")
340 aValue
.Value
<<= o3tl::toInt32(rValue
);
341 else if (rType
== "int16")
342 aValue
.Value
<<= sal_Int16(o3tl::toInt32(rValue
));
343 else if (rType
== "uint64")
344 aValue
.Value
<<= OString(rValue
).toUInt64();
345 else if (rType
== "uint32")
346 aValue
.Value
<<= o3tl::toUInt32(rValue
);
347 else if (rType
== "uint16")
348 aValue
.Value
<<= sal_uInt16(o3tl::toUInt32(rValue
));
349 else if (rType
== "[]byte")
351 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
352 if (aNodeValue
!= aNodeNull
&& aNodeValue
.size() == 0)
354 uno::Sequence
<sal_Int8
> aSeqByte(reinterpret_cast<const sal_Int8
*>(rValue
.c_str()),
356 aValue
.Value
<<= aSeqByte
;
359 else if (rType
== "[]any")
361 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
362 if (aNodeValue
!= aNodeNull
&& !aNodeValue
.empty())
364 uno::Sequence
<uno::Any
> aSeq(aNodeValue
.size());
365 std::transform(aNodeValue
.begin(), aNodeValue
.end(), aSeq
.getArray(),
366 [](const auto& rSeqPair
) { return jsonToUnoAny(rSeqPair
.second
); });
367 aValue
.Value
<<= aSeq
;
370 else if (rType
== "[]com.sun.star.beans.PropertyValue")
372 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
374 boost::property_tree::write_json(s
, aNodeValue
);
375 std::vector
<beans::PropertyValue
> aPropertyValues
= JsonToPropertyValues(OString(s
.str()));
376 aValue
.Value
<<= comphelper::containerToSequence(aPropertyValues
);
378 else if (rType
== "[][]com.sun.star.beans.PropertyValue")
380 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
381 std::vector
<uno::Sequence
<beans::PropertyValue
>> aSeqs
;
382 for (const auto& rItem
: aNodeValue
)
385 boost::property_tree::write_json(s
, rItem
.second
);
386 std::vector
<beans::PropertyValue
> aPropertyValues
= JsonToPropertyValues(OString(s
.str()));
387 aSeqs
.push_back(comphelper::containerToSequence(aPropertyValues
));
389 aValue
.Value
<<= comphelper::containerToSequence(aSeqs
);
392 SAL_WARN("comphelper", "JsonToPropertyValues: unhandled type '" << rType
<< "'");
393 aArguments
.push_back(aValue
);
398 } // namespace comphelper
400 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */