diff options
Diffstat (limited to 'comphelper/source/misc/sequenceashashmap.cxx')
-rw-r--r-- | comphelper/source/misc/sequenceashashmap.cxx | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/comphelper/source/misc/sequenceashashmap.cxx b/comphelper/source/misc/sequenceashashmap.cxx new file mode 100644 index 0000000000..270c005db2 --- /dev/null +++ b/comphelper/source/misc/sequenceashashmap.cxx @@ -0,0 +1,400 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <boost/property_tree/json_parser.hpp> + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/reflection/XIdlField.hpp> +#include <com/sun/star/reflection/theCoreReflection.hpp> +#include <comphelper/sequenceashashmap.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <sal/log.hxx> +#include <o3tl/string_view.hxx> +#include <comphelper/sequence.hxx> + +using namespace com::sun::star; + +namespace +{ +uno::Any jsonToUnoAny(const boost::property_tree::ptree& aTree) +{ + uno::Any aAny; + uno::Any aValue; + sal_Int32 nFields; + uno::Reference<reflection::XIdlField> aField; + boost::property_tree::ptree aNodeNull, aNodeValue, aNodeField; + const std::string& rType = aTree.get<std::string>("type", ""); + const std::string& rValue = aTree.get<std::string>("value", ""); + uno::Sequence<uno::Reference<reflection::XIdlField>> aFields; + uno::Reference<reflection::XIdlClass> xIdlClass + = css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext()) + ->forName(OUString::fromUtf8(rType)); + if (xIdlClass.is()) + { + uno::TypeClass aTypeClass = xIdlClass->getTypeClass(); + xIdlClass->createObject(aAny); + aFields = xIdlClass->getFields(); + nFields = aFields.getLength(); + aNodeValue = aTree.get_child("value", aNodeNull); + if (nFields > 0 && aNodeValue != aNodeNull) + { + for (sal_Int32 itField = 0; itField < nFields; ++itField) + { + aField = aFields[itField]; + aNodeField = aNodeValue.get_child(aField->getName().toUtf8().getStr(), aNodeNull); + if (aNodeField != aNodeNull) + { + aValue = jsonToUnoAny(aNodeField); + aField->set(aAny, aValue); + } + } + } + else if (!rValue.empty()) + { + if (aTypeClass == uno::TypeClass_VOID) + aAny.clear(); + else if (aTypeClass == uno::TypeClass_BYTE) + aAny <<= static_cast<sal_Int8>(o3tl::toInt32(rValue)); + else if (aTypeClass == uno::TypeClass_BOOLEAN) + aAny <<= OString(rValue).toBoolean(); + else if (aTypeClass == uno::TypeClass_SHORT) + aAny <<= static_cast<sal_Int16>(o3tl::toInt32(rValue)); + else if (aTypeClass == uno::TypeClass_UNSIGNED_SHORT) + aAny <<= static_cast<sal_uInt16>(o3tl::toUInt32(rValue)); + else if (aTypeClass == uno::TypeClass_LONG) + aAny <<= o3tl::toInt32(rValue); + else if (aTypeClass == uno::TypeClass_UNSIGNED_LONG) + aAny <<= static_cast<sal_uInt32>(o3tl::toInt32(rValue)); + else if (aTypeClass == uno::TypeClass_FLOAT) + aAny <<= OString(rValue).toFloat(); + else if (aTypeClass == uno::TypeClass_DOUBLE) + aAny <<= o3tl::toDouble(rValue); + else if (aTypeClass == uno::TypeClass_STRING) + aAny <<= OUString::fromUtf8(rValue); + } + } + return aAny; +} +} + +namespace comphelper{ + +SequenceAsHashMap::SequenceAsHashMap() +{ +} + +SequenceAsHashMap::SequenceAsHashMap(const css::uno::Any& aSource) +{ + (*this) << aSource; +} + + +SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::uno::Any >& lSource) +{ + (*this) << lSource; +} + +SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::PropertyValue >& lSource) +{ + (*this) << lSource; +} + +SequenceAsHashMap::SequenceAsHashMap(const css::uno::Sequence< css::beans::NamedValue >& lSource) +{ + (*this) << lSource; +} + +void SequenceAsHashMap::operator<<(const css::uno::Any& aSource) +{ + // An empty Any reset this instance! + if (!aSource.hasValue()) + { + clear(); + return; + } + + css::uno::Sequence< css::beans::NamedValue > lN; + if (aSource >>= lN) + { + (*this) << lN; + return; + } + + css::uno::Sequence< css::beans::PropertyValue > lP; + if (aSource >>= lP) + { + (*this) << lP; + return; + } + + throw css::lang::IllegalArgumentException( + "Any contains wrong type.", css::uno::Reference<css::uno::XInterface>(), + -1); +} + + +void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::uno::Any >& lSource) +{ + sal_Int32 c = lSource.getLength(); + sal_Int32 i = 0; + + m_aMap.reserve(c); + for (i=0; i<c; ++i) + { + css::beans::PropertyValue lP; + if (lSource[i] >>= lP) + { + if ( + (lP.Name.isEmpty()) || + (!lP.Value.hasValue()) + ) + throw css::lang::IllegalArgumentException( + "PropertyValue struct contains no useful information.", + css::uno::Reference<css::uno::XInterface>(), -1); + (*this)[lP.Name] = lP.Value; + continue; + } + + css::beans::NamedValue lN; + if (lSource[i] >>= lN) + { + if ( + (lN.Name.isEmpty()) || + (!lN.Value.hasValue()) + ) + throw css::lang::IllegalArgumentException( + "NamedValue struct contains no useful information.", + css::uno::Reference<css::uno::XInterface>(), -1); + (*this)[lN.Name] = lN.Value; + continue; + } + + // ignore VOID Any ... but reject wrong filled ones! + if (lSource[i].hasValue()) + throw css::lang::IllegalArgumentException( + "Any contains wrong type.", + css::uno::Reference<css::uno::XInterface>(), -1); + } +} + +void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::PropertyValue >& lSource) +{ + clear(); + + sal_Int32 c = lSource.getLength(); + const css::beans::PropertyValue* pSource = lSource.getConstArray(); + + m_aMap.reserve(c); + for (sal_Int32 i=0; i<c; ++i) + (*this)[pSource[i].Name] = pSource[i].Value; +} + +void SequenceAsHashMap::operator<<(const css::uno::Sequence< css::beans::NamedValue >& lSource) +{ + clear(); + + sal_Int32 c = lSource.getLength(); + const css::beans::NamedValue* pSource = lSource.getConstArray(); + + m_aMap.reserve(c); + for (sal_Int32 i=0; i<c; ++i) + (*this)[pSource[i].Name] = pSource[i].Value; +} + +void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::PropertyValue >& lDestination) const +{ + sal_Int32 c = static_cast<sal_Int32>(size()); + lDestination.realloc(c); + css::beans::PropertyValue* pDestination = lDestination.getArray(); + + sal_Int32 i = 0; + for (const_iterator pThis = begin(); + pThis != end() ; + ++pThis ) + { + pDestination[i].Name = pThis->first.maString; + pDestination[i].Value = pThis->second; + ++i; + } +} + +void SequenceAsHashMap::operator>>(css::uno::Sequence< css::beans::NamedValue >& lDestination) const +{ + sal_Int32 c = static_cast<sal_Int32>(size()); + lDestination.realloc(c); + css::beans::NamedValue* pDestination = lDestination.getArray(); + + sal_Int32 i = 0; + for (const_iterator pThis = begin(); + pThis != end() ; + ++pThis ) + { + pDestination[i].Name = pThis->first.maString; + pDestination[i].Value = pThis->second; + ++i; + } +} + +css::uno::Any SequenceAsHashMap::getAsConstAny(bool bAsPropertyValueList) const +{ + css::uno::Any aDestination; + if (bAsPropertyValueList) + aDestination <<= getAsConstPropertyValueList(); + else + aDestination <<= getAsConstNamedValueList(); + return aDestination; +} + +css::uno::Sequence< css::beans::NamedValue > SequenceAsHashMap::getAsConstNamedValueList() const +{ + css::uno::Sequence< css::beans::NamedValue > lReturn; + (*this) >> lReturn; + return lReturn; +} + +css::uno::Sequence< css::beans::PropertyValue > SequenceAsHashMap::getAsConstPropertyValueList() const +{ + css::uno::Sequence< css::beans::PropertyValue > lReturn; + (*this) >> lReturn; + return lReturn; +} + +bool SequenceAsHashMap::match(const SequenceAsHashMap& rCheck) const +{ + for (auto const& elem : rCheck) + { + const OUString& sCheckName = elem.first.maString; + const css::uno::Any& aCheckValue = elem.second; + const_iterator pFound = find(sCheckName); + + if (pFound == end()) + return false; + + const css::uno::Any& aFoundValue = pFound->second; + if (aFoundValue != aCheckValue) + return false; + } + + return true; +} + +void SequenceAsHashMap::update(const SequenceAsHashMap& rUpdate) +{ + m_aMap.reserve(std::max(size(), rUpdate.size())); + for (auto const& elem : rUpdate.m_aMap) + { + m_aMap[elem.first] = elem.second; + } +} + +std::vector<css::beans::PropertyValue> JsonToPropertyValues(const OString& rJson) +{ + std::vector<beans::PropertyValue> aArguments; + boost::property_tree::ptree aTree, aNodeNull, aNodeValue; + std::stringstream aStream((std::string(rJson))); + boost::property_tree::read_json(aStream, aTree); + + for (const auto& rPair : aTree) + { + const std::string& rType = rPair.second.get<std::string>("type", ""); + const std::string& rValue = rPair.second.get<std::string>("value", ""); + + beans::PropertyValue aValue; + aValue.Name = OUString::fromUtf8(rPair.first); + if (rType == "string") + aValue.Value <<= OUString::fromUtf8(rValue); + else if (rType == "boolean") + aValue.Value <<= OString(rValue).toBoolean(); + else if (rType == "float") + aValue.Value <<= OString(rValue).toFloat(); + else if (rType == "long") + aValue.Value <<= o3tl::toInt32(rValue); + else if (rType == "short") + aValue.Value <<= sal_Int16(o3tl::toInt32(rValue)); + else if (rType == "unsigned short") + aValue.Value <<= sal_uInt16(o3tl::toUInt32(rValue)); + else if (rType == "int64") + aValue.Value <<= o3tl::toInt64(rValue); + else if (rType == "int32") + aValue.Value <<= o3tl::toInt32(rValue); + else if (rType == "int16") + aValue.Value <<= sal_Int16(o3tl::toInt32(rValue)); + else if (rType == "uint64") + aValue.Value <<= OString(rValue).toUInt64(); + else if (rType == "uint32") + aValue.Value <<= o3tl::toUInt32(rValue); + else if (rType == "uint16") + aValue.Value <<= sal_uInt16(o3tl::toUInt32(rValue)); + else if (rType == "[]byte") + { + aNodeValue = rPair.second.get_child("value", aNodeNull); + if (aNodeValue != aNodeNull && aNodeValue.size() == 0) + { + uno::Sequence<sal_Int8> aSeqByte(reinterpret_cast<const sal_Int8*>(rValue.c_str()), + rValue.size()); + aValue.Value <<= aSeqByte; + } + } + else if (rType == "[]any") + { + aNodeValue = rPair.second.get_child("value", aNodeNull); + if (aNodeValue != aNodeNull && !aNodeValue.empty()) + { + uno::Sequence<uno::Any> aSeq(aNodeValue.size()); + std::transform(aNodeValue.begin(), aNodeValue.end(), aSeq.getArray(), + [](const auto& rSeqPair) { return jsonToUnoAny(rSeqPair.second); }); + aValue.Value <<= aSeq; + } + } + else if (rType == "[]com.sun.star.beans.PropertyValue") + { + aNodeValue = rPair.second.get_child("value", aNodeNull); + std::stringstream s; + boost::property_tree::write_json(s, aNodeValue); + std::vector<beans::PropertyValue> aPropertyValues = JsonToPropertyValues(OString(s.str())); + aValue.Value <<= comphelper::containerToSequence(aPropertyValues); + } + else if (rType == "[][]com.sun.star.beans.PropertyValue") + { + aNodeValue = rPair.second.get_child("value", aNodeNull); + std::vector<uno::Sequence<beans::PropertyValue>> aSeqs; + for (const auto& rItem : aNodeValue) + { + std::stringstream s; + boost::property_tree::write_json(s, rItem.second); + std::vector<beans::PropertyValue> aPropertyValues = JsonToPropertyValues(OString(s.str())); + aSeqs.push_back(comphelper::containerToSequence(aPropertyValues)); + } + aValue.Value <<= comphelper::containerToSequence(aSeqs); + } + else + SAL_WARN("comphelper", "JsonToPropertyValues: unhandled type '" << rType << "'"); + aArguments.push_back(aValue); + } + return aArguments; +} + +} // namespace comphelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |