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>
34 
35 using namespace com::sun::star;
36 
37 namespace
38 {
39 uno::Any jsonToUnoAny(const boost::property_tree::ptree& aTree)
40 {
41  uno::Any aAny;
42  uno::Any aValue;
43  sal_Int32 nFields;
44  uno::Reference<reflection::XIdlField> aField;
45  boost::property_tree::ptree aNodeNull, aNodeValue, aNodeField;
46  const std::string& rType = aTree.get<std::string>("type", "");
47  const std::string& rValue = aTree.get<std::string>("value", "");
48  uno::Sequence<uno::Reference<reflection::XIdlField>> aFields;
49  uno::Reference<reflection::XIdlClass> xIdlClass
50  = css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())
51  ->forName(OUString::fromUtf8(rType.c_str()));
52  if (xIdlClass.is())
53  {
54  uno::TypeClass aTypeClass = xIdlClass->getTypeClass();
55  xIdlClass->createObject(aAny);
56  aFields = xIdlClass->getFields();
57  nFields = aFields.getLength();
58  aNodeValue = aTree.get_child("value", aNodeNull);
59  if (nFields > 0 && aNodeValue != aNodeNull)
60  {
61  for (sal_Int32 itField = 0; itField < nFields; ++itField)
62  {
63  aField = aFields[itField];
64  aNodeField = aNodeValue.get_child(aField->getName().toUtf8().getStr(), aNodeNull);
65  if (aNodeField != aNodeNull)
66  {
67  aValue = jsonToUnoAny(aNodeField);
68  aField->set(aAny, aValue);
69  }
70  }
71  }
72  else if (!rValue.empty())
73  {
74  if (aTypeClass == uno::TypeClass_VOID)
75  aAny.clear();
76  else if (aTypeClass == uno::TypeClass_BYTE)
77  aAny <<= static_cast<sal_Int8>(o3tl::toInt32(rValue));
78  else if (aTypeClass == uno::TypeClass_BOOLEAN)
79  aAny <<= OString(rValue.c_str()).toBoolean();
80  else if (aTypeClass == uno::TypeClass_SHORT)
81  aAny <<= static_cast<sal_Int16>(o3tl::toInt32(rValue));
82  else if (aTypeClass == uno::TypeClass_UNSIGNED_SHORT)
83  aAny <<= static_cast<sal_uInt16>(o3tl::toUInt32(rValue));
84  else if (aTypeClass == uno::TypeClass_LONG)
85  aAny <<= o3tl::toInt32(rValue);
86  else if (aTypeClass == uno::TypeClass_UNSIGNED_LONG)
87  aAny <<= static_cast<sal_uInt32>(o3tl::toInt32(rValue));
88  else if (aTypeClass == uno::TypeClass_FLOAT)
89  aAny <<= OString(rValue.c_str()).toFloat();
90  else if (aTypeClass == uno::TypeClass_DOUBLE)
91  aAny <<= o3tl::toDouble(rValue);
92  else if (aTypeClass == uno::TypeClass_STRING)
93  aAny <<= OUString::fromUtf8(rValue.c_str());
94  }
95  }
96  return aAny;
97 }
98 }
99 
100 namespace comphelper{
101 
102 SequenceAsHashMap::SequenceAsHashMap()
103 {
104 }
105 
106 SequenceAsHashMap::SequenceAsHashMap(const css::uno::Any& aSource)
107 {
108  (*this) << aSource;
109 }
110 
111 
112 SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::uno::Any >& lSource)
113 {
114  (*this) << lSource;
115 }
116 
117 SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
118 {
119  (*this) << lSource;
120 }
121 
122 SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::NamedValue >& lSource)
123 {
124  (*this) << lSource;
125 }
126 
127 void SequenceAsHashMap::operator<<(const css::uno::Any& aSource)
128 {
129  // An empty Any reset this instance!
130  if (!aSource.hasValue())
131  {
132  clear();
133  return;
134  }
135 
136  css::uno::Sequence< css::beans::NamedValue > lN;
137  if (aSource >>= lN)
138  {
139  (*this) << lN;
140  return;
141  }
142 
143  css::uno::Sequence< css::beans::PropertyValue > lP;
144  if (aSource >>= lP)
145  {
146  (*this) << lP;
147  return;
148  }
149 
150  throw css::lang::IllegalArgumentException(
151  "Any contains wrong type.", css::uno::Reference<css::uno::XInterface>(),
152  -1);
153 }
154 
155 
156 void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::uno::Any >& lSource)
157 {
158  sal_Int32 c = lSource.getLength();
159  sal_Int32 i = 0;
160 
161  m_aMap.reserve(c);
162  for (i=0; i<c; ++i)
163  {
164  css::beans::PropertyValue lP;
165  if (lSource[i] >>= lP)
166  {
167  if (
168  (lP.Name.isEmpty()) ||
169  (!lP.Value.hasValue())
170  )
171  throw css::lang::IllegalArgumentException(
172  "PropertyValue struct contains no useful information.",
173  css::uno::Reference<css::uno::XInterface>(), -1);
174  (*this)[lP.Name] = lP.Value;
175  continue;
176  }
177 
178  css::beans::NamedValue lN;
179  if (lSource[i] >>= lN)
180  {
181  if (
182  (lN.Name.isEmpty()) ||
183  (!lN.Value.hasValue())
184  )
185  throw css::lang::IllegalArgumentException(
186  "NamedValue struct contains no useful information.",
187  css::uno::Reference<css::uno::XInterface>(), -1);
188  (*this)[lN.Name] = lN.Value;
189  continue;
190  }
191 
192  // ignore VOID Any ... but reject wrong filled ones!
193  if (lSource[i].hasValue())
194  throw css::lang::IllegalArgumentException(
195  "Any contains wrong type.",
196  css::uno::Reference<css::uno::XInterface>(), -1);
197  }
198 }
199 
200 void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
201 {
202  clear();
203 
204  sal_Int32 c = lSource.getLength();
205  const css::beans::PropertyValue* pSource = lSource.getConstArray();
206 
207  m_aMap.reserve(c);
208  for (sal_Int32 i=0; i<c; ++i)
209  (*this)[pSource[i].Name] = pSource[i].Value;
210 }
211 
212 void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::NamedValue >& lSource)
213 {
214  clear();
215 
216  sal_Int32 c = lSource.getLength();
217  const css::beans::NamedValue* pSource = lSource.getConstArray();
218 
219  m_aMap.reserve(c);
220  for (sal_Int32 i=0; i<c; ++i)
221  (*this)[pSource[i].Name] = pSource[i].Value;
222 }
223 
224 void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::PropertyValue >& lDestination) const
225 {
226  sal_Int32 c = static_cast<sal_Int32>(size());
227  lDestination.realloc(c);
228  css::beans::PropertyValue* pDestination = lDestination.getArray();
229 
230  sal_Int32 i = 0;
231  for (const_iterator pThis = begin();
232  pThis != end() ;
233  ++pThis )
234  {
235  pDestination[i].Name = pThis->first.maString;
236  pDestination[i].Value = pThis->second;
237  ++i;
238  }
239 }
240 
241 void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::NamedValue >& lDestination) const
242 {
243  sal_Int32 c = static_cast<sal_Int32>(size());
244  lDestination.realloc(c);
245  css::beans::NamedValue* pDestination = lDestination.getArray();
246 
247  sal_Int32 i = 0;
248  for (const_iterator pThis = begin();
249  pThis != end() ;
250  ++pThis )
251  {
252  pDestination[i].Name = pThis->first.maString;
253  pDestination[i].Value = pThis->second;
254  ++i;
255  }
256 }
257 
258 css::uno::Any SequenceAsHashMap::getAsConstAny(bool bAsPropertyValueList) const
259 {
260  css::uno::Any aDestination;
261  if (bAsPropertyValueList)
262  aDestination <<= getAsConstPropertyValueList();
263  else
264  aDestination <<= getAsConstNamedValueList();
265  return aDestination;
266 }
267 
268 css::uno::Sequence< css::beans::NamedValue > SequenceAsHashMap::getAsConstNamedValueList() const
269 {
270  css::uno::Sequence< css::beans::NamedValue > lReturn;
271  (*this) >> lReturn;
272  return lReturn;
273 }
274 
275 css::uno::Sequence< css::beans::PropertyValue > SequenceAsHashMap::getAsConstPropertyValueList() const
276 {
277  css::uno::Sequence< css::beans::PropertyValue > lReturn;
278  (*this) >> lReturn;
279  return lReturn;
280 }
281 
282 bool SequenceAsHashMap::match(const SequenceAsHashMap& rCheck) const
283 {
284  for (auto const& elem : rCheck)
285  {
286  const OUString& sCheckName = elem.first.maString;
287  const css::uno::Any& aCheckValue = elem.second;
288  const_iterator pFound = find(sCheckName);
289 
290  if (pFound == end())
291  return false;
292 
293  const css::uno::Any& aFoundValue = pFound->second;
294  if (aFoundValue != aCheckValue)
295  return false;
296  }
297 
298  return true;
299 }
300 
301 void SequenceAsHashMap::update(const SequenceAsHashMap& rUpdate)
302 {
303  m_aMap.reserve(std::max(size(), rUpdate.size()));
304  for (auto const& elem : rUpdate.m_aMap)
305  {
306  m_aMap[elem.first] = elem.second;
307  }
308 }
309 
310 std::vector<css::beans::PropertyValue> JsonToPropertyValues(const OString& rJson)
311 {
312  std::vector<beans::PropertyValue> aArguments;
313  boost::property_tree::ptree aTree, aNodeNull, aNodeValue;
314  std::stringstream aStream(rJson.getStr());
315  boost::property_tree::read_json(aStream, aTree);
316 
317  for (const auto& rPair : aTree)
318  {
319  const std::string& rType = rPair.second.get<std::string>("type", "");
320  const std::string& rValue = rPair.second.get<std::string>("value", "");
321 
322  beans::PropertyValue aValue;
323  aValue.Name = OUString::fromUtf8(rPair.first.c_str());
324  if (rType == "string")
325  aValue.Value <<= OUString::fromUtf8(rValue.c_str());
326  else if (rType == "boolean")
327  aValue.Value <<= OString(rValue.c_str()).toBoolean();
328  else if (rType == "float")
329  aValue.Value <<= OString(rValue.c_str()).toFloat();
330  else if (rType == "long")
331  aValue.Value <<= o3tl::toInt32(rValue);
332  else if (rType == "short")
333  aValue.Value <<= sal_Int16(o3tl::toInt32(rValue));
334  else if (rType == "unsigned short")
335  aValue.Value <<= sal_uInt16(o3tl::toUInt32(rValue));
336  else if (rType == "int64")
337  aValue.Value <<= o3tl::toInt64(rValue);
338  else if (rType == "int32")
339  aValue.Value <<= o3tl::toInt32(rValue);
340  else if (rType == "int16")
341  aValue.Value <<= sal_Int16(o3tl::toInt32(rValue));
342  else if (rType == "uint64")
343  aValue.Value <<= OString(rValue.c_str()).toUInt64();
344  else if (rType == "uint32")
345  aValue.Value <<= o3tl::toUInt32(rValue);
346  else if (rType == "uint16")
347  aValue.Value <<= sal_uInt16(o3tl::toUInt32(rValue));
348  else if (rType == "[]byte")
349  {
350  aNodeValue = rPair.second.get_child("value", aNodeNull);
351  if (aNodeValue != aNodeNull && aNodeValue.size() == 0)
352  {
353  uno::Sequence<sal_Int8> aSeqByte(reinterpret_cast<const sal_Int8*>(rValue.c_str()),
354  rValue.size());
355  aValue.Value <<= aSeqByte;
356  }
357  }
358  else if (rType == "[]any")
359  {
360  aNodeValue = rPair.second.get_child("value", aNodeNull);
361  if (aNodeValue != aNodeNull && !aNodeValue.empty())
362  {
363  uno::Sequence<uno::Any> aSeq(aNodeValue.size());
364  std::transform(aNodeValue.begin(), aNodeValue.end(), aSeq.getArray(),
365  [](const auto& rSeqPair) { return jsonToUnoAny(rSeqPair.second); });
366  aValue.Value <<= aSeq;
367  }
368  }
369  else
370  SAL_WARN("comphelper", "JsonToPropertyValues: unhandled type '" << rType << "'");
371  aArguments.push_back(aValue);
372  }
373  return aArguments;
374 }
375 
376 } // namespace comphelper
377 
378 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SequenceAsHashMapBase::const_iterator const_iterator
sal_Int64 toInt64(std::u16string_view str, sal_Int16 radix=10)
Sequence< PropertyValue > aArguments
enumrange< T >::Iterator begin(enumrange< T >)
std::vector< css::beans::PropertyValue > JsonToPropertyValues(const OString &rJson)
const css::uno::Reference< css::io::XObjectOutputStream > & operator<<(const css::uno::Reference< css::io::XObjectOutputStream > &_rxOutStream, const css::awt::FontDescriptor &_rFont)
Definition: basicio.cxx:29
double toDouble(std::u16string_view str)
int i
Object Value
size
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
enumrange< T >::Iterator end(enumrange< T >)
static PropertyMapEntry const * find(const rtl::Reference< PropertySetInfo > &mxInfo, const OUString &aName) noexcept
const css::uno::Reference< css::io::XObjectInputStream > & operator>>(const css::uno::Reference< css::io::XObjectInputStream > &_rxInStream, css::awt::FontDescriptor &_rFont)
Definition: basicio.cxx:54
sal_uInt32 toUInt32(std::u16string_view str, sal_Int16 radix=10)
Reference< XComponentContext > getProcessComponentContext()
This function gets the process service factory's default component context.
Sequence< sal_Int8 > aSeq
#define SAL_WARN(area, stream)