LibreOffice Module comphelper (master) 1
sequenceashashmap.cxx
Go to the documentation of this file.
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>
32#include <sal/log.hxx>
33#include <o3tl/string_view.hxx>
35
36using namespace com::sun::star;
37
38namespace
39{
40uno::Any jsonToUnoAny(const boost::property_tree::ptree& aTree)
41{
42 uno::Any aAny;
43 uno::Any aValue;
44 sal_Int32 nFields;
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));
53 if (xIdlClass.is())
54 {
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)
61 {
62 for (sal_Int32 itField = 0; itField < nFields; ++itField)
63 {
64 aField = aFields[itField];
65 aNodeField = aNodeValue.get_child(aField->getName().toUtf8().getStr(), aNodeNull);
66 if (aNodeField != aNodeNull)
67 {
68 aValue = jsonToUnoAny(aNodeField);
69 aField->set(aAny, aValue);
70 }
71 }
72 }
73 else if (!rValue.empty())
74 {
75 if (aTypeClass == uno::TypeClass_VOID)
76 aAny.clear();
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);
95 }
96 }
97 return aAny;
98}
99}
100
101namespace comphelper{
102
104{
105}
106
107SequenceAsHashMap::SequenceAsHashMap(const css::uno::Any& aSource)
108{
109 (*this) << aSource;
110}
111
112
113SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::uno::Any >& lSource)
114{
115 (*this) << lSource;
116}
117
118SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
119{
120 (*this) << lSource;
121}
122
123SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::NamedValue >& lSource)
124{
125 (*this) << lSource;
126}
127
128void SequenceAsHashMap::operator<<(const css::uno::Any& aSource)
129{
130 // An empty Any reset this instance!
131 if (!aSource.hasValue())
132 {
133 clear();
134 return;
135 }
136
137 css::uno::Sequence< css::beans::NamedValue > lN;
138 if (aSource >>= lN)
139 {
140 (*this) << lN;
141 return;
142 }
143
144 css::uno::Sequence< css::beans::PropertyValue > lP;
145 if (aSource >>= lP)
146 {
147 (*this) << lP;
148 return;
149 }
150
151 throw css::lang::IllegalArgumentException(
152 "Any contains wrong type.", css::uno::Reference<css::uno::XInterface>(),
153 -1);
154}
155
156
157void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::uno::Any >& lSource)
158{
159 sal_Int32 c = lSource.getLength();
160 sal_Int32 i = 0;
161
162 m_aMap.reserve(c);
163 for (i=0; i<c; ++i)
164 {
165 css::beans::PropertyValue lP;
166 if (lSource[i] >>= lP)
167 {
168 if (
169 (lP.Name.isEmpty()) ||
170 (!lP.Value.hasValue())
171 )
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;
176 continue;
177 }
178
179 css::beans::NamedValue lN;
180 if (lSource[i] >>= lN)
181 {
182 if (
183 (lN.Name.isEmpty()) ||
184 (!lN.Value.hasValue())
185 )
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;
190 continue;
191 }
192
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);
198 }
199}
200
201void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
202{
203 clear();
204
205 sal_Int32 c = lSource.getLength();
206 const css::beans::PropertyValue* pSource = lSource.getConstArray();
207
208 m_aMap.reserve(c);
209 for (sal_Int32 i=0; i<c; ++i)
210 (*this)[pSource[i].Name] = pSource[i].Value;
211}
212
213void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::NamedValue >& lSource)
214{
215 clear();
216
217 sal_Int32 c = lSource.getLength();
218 const css::beans::NamedValue* pSource = lSource.getConstArray();
219
220 m_aMap.reserve(c);
221 for (sal_Int32 i=0; i<c; ++i)
222 (*this)[pSource[i].Name] = pSource[i].Value;
223}
224
225void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::PropertyValue >& lDestination) const
226{
227 sal_Int32 c = static_cast<sal_Int32>(size());
228 lDestination.realloc(c);
229 css::beans::PropertyValue* pDestination = lDestination.getArray();
230
231 sal_Int32 i = 0;
232 for (const_iterator pThis = begin();
233 pThis != end() ;
234 ++pThis )
235 {
236 pDestination[i].Name = pThis->first.maString;
237 pDestination[i].Value = pThis->second;
238 ++i;
239 }
240}
241
242void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::NamedValue >& lDestination) const
243{
244 sal_Int32 c = static_cast<sal_Int32>(size());
245 lDestination.realloc(c);
246 css::beans::NamedValue* pDestination = lDestination.getArray();
247
248 sal_Int32 i = 0;
249 for (const_iterator pThis = begin();
250 pThis != end() ;
251 ++pThis )
252 {
253 pDestination[i].Name = pThis->first.maString;
254 pDestination[i].Value = pThis->second;
255 ++i;
256 }
257}
258
259css::uno::Any SequenceAsHashMap::getAsConstAny(bool bAsPropertyValueList) const
260{
261 css::uno::Any aDestination;
262 if (bAsPropertyValueList)
263 aDestination <<= getAsConstPropertyValueList();
264 else
265 aDestination <<= getAsConstNamedValueList();
266 return aDestination;
267}
268
269css::uno::Sequence< css::beans::NamedValue > SequenceAsHashMap::getAsConstNamedValueList() const
270{
271 css::uno::Sequence< css::beans::NamedValue > lReturn;
272 (*this) >> lReturn;
273 return lReturn;
274}
275
276css::uno::Sequence< css::beans::PropertyValue > SequenceAsHashMap::getAsConstPropertyValueList() const
277{
278 css::uno::Sequence< css::beans::PropertyValue > lReturn;
279 (*this) >> lReturn;
280 return lReturn;
281}
282
284{
285 for (auto const& elem : rCheck)
286 {
287 const OUString& sCheckName = elem.first.maString;
288 const css::uno::Any& aCheckValue = elem.second;
289 const_iterator pFound = find(sCheckName);
290
291 if (pFound == end())
292 return false;
293
294 const css::uno::Any& aFoundValue = pFound->second;
295 if (aFoundValue != aCheckValue)
296 return false;
297 }
298
299 return true;
300}
301
303{
304 m_aMap.reserve(std::max(size(), rUpdate.size()));
305 for (auto const& elem : rUpdate.m_aMap)
306 {
307 m_aMap[elem.first] = elem.second;
308 }
309}
310
311std::vector<css::beans::PropertyValue> JsonToPropertyValues(const OString& rJson)
312{
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);
317
318 for (const auto& rPair : aTree)
319 {
320 const std::string& rType = rPair.second.get<std::string>("type", "");
321 const std::string& rValue = rPair.second.get<std::string>("value", "");
322
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")
350 {
351 aNodeValue = rPair.second.get_child("value", aNodeNull);
352 if (aNodeValue != aNodeNull && aNodeValue.size() == 0)
353 {
354 uno::Sequence<sal_Int8> aSeqByte(reinterpret_cast<const sal_Int8*>(rValue.c_str()),
355 rValue.size());
356 aValue.Value <<= aSeqByte;
357 }
358 }
359 else if (rType == "[]any")
360 {
361 aNodeValue = rPair.second.get_child("value", aNodeNull);
362 if (aNodeValue != aNodeNull && !aNodeValue.empty())
363 {
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;
368 }
369 }
370 else if (rType == "[]com.sun.star.beans.PropertyValue")
371 {
372 aNodeValue = rPair.second.get_child("value", aNodeNull);
373 std::stringstream s;
374 boost::property_tree::write_json(s, aNodeValue);
375 std::vector<beans::PropertyValue> aPropertyValues = JsonToPropertyValues(OString(s.str()));
377 }
378 else if (rType == "[][]com.sun.star.beans.PropertyValue")
379 {
380 aNodeValue = rPair.second.get_child("value", aNodeNull);
381 std::vector<uno::Sequence<beans::PropertyValue>> aSeqs;
382 for (const auto& rItem : aNodeValue)
383 {
384 std::stringstream s;
385 boost::property_tree::write_json(s, rItem.second);
386 std::vector<beans::PropertyValue> aPropertyValues = JsonToPropertyValues(OString(s.str()));
388 }
389 aValue.Value <<= comphelper::containerToSequence(aSeqs);
390 }
391 else
392 SAL_WARN("comphelper", "JsonToPropertyValues: unhandled type '" << rType << "'");
393 aArguments.push_back(aValue);
394 }
395 return aArguments;
396}
397
398} // namespace comphelper
399
400/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PropertyValueVector_t aPropertyValues
css::uno::Any getAsConstAny(bool bAsPropertyValue) const
return this map instance as an Any, which can be used in const environments only.
void operator>>(css::uno::Sequence< css::beans::PropertyValue > &lDestination) const
converts this map instance to an PropertyValue sequence.
iterator find(const OUString &rKey)
css::uno::Sequence< css::beans::PropertyValue > getAsConstPropertyValueList() const
return this map instance to as a PropertyValue sequence, which can be used in const environments only...
void update(const SequenceAsHashMap &rSource)
merge all values from the given map into this one.
bool match(const SequenceAsHashMap &rCheck) const
check if all items of given map exists in these called map also.
SequenceAsHashMapBase::const_iterator const_iterator
void operator<<(const css::uno::Any &aSource)
fill this map from the given Any, which of course must contain a suitable sequence of element types "...
css::uno::Sequence< css::beans::NamedValue > getAsConstNamedValueList() const
return this map instance to as a NamedValue sequence, which can be used in const environments only.
SequenceAsHashMap()
creates an empty hash map.
Sequence< PropertyValue > aArguments
Sequence< sal_Int8 > aSeq
#define SAL_WARN(area, stream)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Copy from a container into a Sequence.
Definition: sequence.hxx:190
std::vector< css::beans::PropertyValue > JsonToPropertyValues(const OString &rJson)
Reference< XComponentContext > getProcessComponentContext()
This function gets the process service factory's default component context.
int i
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
sal_Int64 toInt64(std::u16string_view str, sal_Int16 radix=10)
double toDouble(std::u16string_view str)
sal_uInt32 toUInt32(std::u16string_view str, sal_Int16 radix=10)
signed char sal_Int8