/* * MIT License * * Copyright (c) 2019 Alexey Edelev * * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and * to permit persons to whom the Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be included in all copies * or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "qprotobufserializerregistry_p.h" #include "qprotobufserializer.h" #include "qprotobufjsonserializer.h" #include "qprotobufserializationplugininterface.h" #include #include #include #include #include #include namespace { const QLatin1String Serializationplugin("serializationplugin"); const QLatin1String TypeNames("types"); const QLatin1String MetaData("MetaData"); const QLatin1String Version("version"); const QLatin1String Rating("rating"); const QLatin1String ProtoVersion("protobufVersion"); const QLatin1String PluginName("name"); const QLatin1String ProtobufSerializer("protobuf"); const QLatin1String JsonSerializer("json"); #ifdef _WIN32 const QLatin1String libExtension(".dll"); const QLatin1String libPrefix(""); #else const QLatin1String libExtension(".so"); const QLatin1String libPrefix("lib"); #endif } #define STRINGIFY2(s) #s #define STRINGIFY(s) STRINGIFY2(s) static const char *QtProtobufPluginPath = STRINGIFY(QT_PROTOBUF_PLUGIN_PATH)"/"; namespace QtProtobuf { class QProtobufSerializerRegistryPrivateRecord final { public: QProtobufSerializerRegistryPrivateRecord() : loader(nullptr) {} void createDefaultImpl() { if (serializers.find(ProtobufSerializer) == serializers.end()) { serializers[ProtobufSerializer] = std::shared_ptr(new QProtobufSerializer); } if (serializers.find(JsonSerializer) == serializers.end()) { serializers[JsonSerializer] = std::shared_ptr(new QProtobufJsonSerializer); } } void loadPluginMetadata(const QString &path, const QString &pluginName) { // Load default plugin if (path.isEmpty() || pluginName.isEmpty()){ libPath = QtProtobufPluginPath + libPrefix + Serializationplugin + libExtension; } // Use custom plugin else { libPath = path + libPrefix + pluginName + libExtension; } loader = new QPluginLoader(libPath); pluginData = loader->metaData(); QVariantMap fullJson = pluginData.toVariantMap(); if (!fullJson.isEmpty()) { metaData = fullJson.value(MetaData).toMap(); pluginLoadedName = metaData.value(PluginName).toString(); typeArray = metaData.value(TypeNames).toList(); } } void loadPlugin() { QProtobufSerializationPluginInterface *loadedPlugin = qobject_cast(loadPluginImpl()); if (!pluginData.isEmpty() && loadedPlugin) { for (int i = 0; i < typeArray.count(); i++) { QString typeName = typeArray.at(i).toString(); serializers[typeName] = std::shared_ptr(loadedPlugin->serializer(typeName)); } } } QObject* loadPluginImpl() { if (loader == nullptr || !loader->load()) { qProtoWarning() << "Can't load plugin from" << libPath << loader->errorString(); return nullptr; } return loader->instance(); } std::unordered_map> serializers; QJsonObject pluginData; QVariantMap metaData; QString pluginLoadedName; QPluginLoader *loader; QString libPath; QVariantList typeArray; }; class QProtobufSerializerRegistryPrivate { public: QProtobufSerializerRegistryPrivate() { // create default impl std::shared_ptr plugin = std::shared_ptr(new QProtobufSerializerRegistryPrivateRecord()); plugin->createDefaultImpl(); m_plugins[DefaultImpl] = plugin; } static const QString &loadPlugin(const QString &path, const QString &name) { std::shared_ptr plugin = std::shared_ptr(new QProtobufSerializerRegistryPrivateRecord()); plugin->loadPluginMetadata(path, name); const QString &pluginName = plugin->pluginLoadedName; if (m_plugins.find(pluginName) == m_plugins.end()) { plugin->loadPlugin(); m_plugins[pluginName] = plugin; } return pluginName; } static std::unordered_map> m_plugins; }; std::unordered_map> QProtobufSerializerRegistryPrivate::m_plugins; } using namespace QtProtobuf; QProtobufSerializerRegistry::QProtobufSerializerRegistry() : dPtr(new QProtobufSerializerRegistryPrivate()) { } QProtobufSerializerRegistry::~QProtobufSerializerRegistry() = default; const QString &QProtobufSerializerRegistry::loadPlugin(const QString &path, const QString &name) { return dPtr->loadPlugin(path, name); } std::shared_ptr QProtobufSerializerRegistry::getSerializer(const QString &id, const QString &plugin) { return dPtr->m_plugins[plugin]->serializers.at(id); //throws } std::unique_ptr QProtobufSerializerRegistry::acquireSerializer(const QString &/*id*/, const QString &/*plugin*/) { Q_ASSERT_X(false, "QProtobufSerializerRegistry", "acquireSerializer is unimplemented"); return std::unique_ptr(); } float QProtobufSerializerRegistry::pluginVersion(const QString &plugin) { if (dPtr->m_plugins.find(plugin) == dPtr->m_plugins.end()) return 0.0; std::shared_ptr implementation = dPtr->m_plugins[plugin]; if (implementation->metaData.isEmpty()) return 0.0; return implementation->metaData.value(Version).toFloat(); } QStringList QProtobufSerializerRegistry::pluginSerializers(const QString &plugin) { QStringList strList; if (dPtr->m_plugins.find(plugin) == dPtr->m_plugins.end()) return strList; std::shared_ptr implementation = dPtr->m_plugins[plugin]; QVariantList typeArray = implementation->metaData.value(TypeNames).toList(); foreach(QVariant value, typeArray) { if (!value.toString().isEmpty()) { strList.append(value.toString()); } } return strList; } float QProtobufSerializerRegistry::pluginProtobufVersion(const QString &plugin) { if (dPtr->m_plugins.find(plugin) == dPtr->m_plugins.end()) return 0.0; std::shared_ptr implementation = dPtr->m_plugins[plugin]; if (implementation.get() && implementation->metaData.isEmpty()) return 0.0; return implementation->metaData.value(ProtoVersion).toFloat(); } int QProtobufSerializerRegistry::pluginRating(const QString &plugin) { if (dPtr->m_plugins.find(plugin) == dPtr->m_plugins.end()) return 0; std::shared_ptr implementation = dPtr->m_plugins[plugin]; if (implementation->metaData.isEmpty()) return 0; return implementation->metaData.value(Rating).toInt(); }