/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: */ |