1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2004-2021 musikcube team
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 //    * Redistributions of source code must retain the above copyright notice,
11 //      this list of conditions and the following disclaimer.
12 //
13 //    * Redistributions in binary form must reproduce the above copyright
14 //      notice, this list of conditions and the following disclaimer in the
15 //      documentation and/or other materials provided with the distribution.
16 //
17 //    * Neither the name of the author nor the names of other contributors may
18 //      be used to endorse or promote products derived from this software
19 //      without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 //
33 //////////////////////////////////////////////////////////////////////////////
34 
35 #pragma once
36 
37 #include <musikcore/config.h>
38 #include <musikcore/sdk/IPlugin.h>
39 #include <musikcore/sdk/IPreferences.h>
40 
41 #include <vector>
42 #include <iostream>
43 #include <string>
44 #include <memory>
45 #include <mutex>
46 
47 #ifdef WIN32
48     #define STDCALL(fp) (__stdcall* fp)()
49 #else
50     #include <dlfcn.h>
51     #define STDCALL(fp) (* fp)()
52 #endif
53 
54 namespace musik { namespace core {
55 
56     class PluginFactory {
57         public:
58             static PluginFactory& Instance();
59 
60             template <typename T>
61             struct ReleaseDeleter {
operatorReleaseDeleter62                 void operator()(T* t) {
63                     t->Release();
64                 }
65             };
66 
67             template <typename T>
68             struct NullDeleter {
operatorNullDeleter69                 void operator()(T* t) {
70                 }
71             };
72 
QueryInterface(const std::string & functionName,std::function<void (musik::core::sdk::IPlugin *,std::shared_ptr<T>,const std::string &)> handler)73             template <class T, class D> void QueryInterface(
74                 const std::string& functionName,
75                 std::function<void(musik::core::sdk::IPlugin*, std::shared_ptr<T>, const std::string&)> handler)
76             {
77                 std::unique_lock<std::mutex> lock(this->mutex);
78 
79                 typedef T* STDCALL(PluginInterfaceCall);
80 
81                 for (std::shared_ptr<Descriptor> descriptor : this->plugins) {
82                     if (functionName == "GetPlugin" || prefs->GetBool(descriptor->key.c_str(), true)) { /* enabled */
83                         PluginInterfaceCall funcPtr =
84 #ifdef WIN32
85                             (PluginInterfaceCall) GetProcAddress((HMODULE)(descriptor->nativeHandle), functionName.c_str());
86 #else
87                             (PluginInterfaceCall)dlsym(descriptor->nativeHandle, functionName.c_str());
88 #endif
89                         if (funcPtr) {
90                             T* result = funcPtr();
91 
92                             if (result) {
93                                 handler(descriptor->plugin, std::shared_ptr<T>(result, D()), descriptor->filename);
94                             }
95                         }
96                     }
97                 }
98             }
99 
QueryInterface(const std::string & functionName)100             template <class T, class D> std::vector<std::shared_ptr<T> > QueryInterface(const std::string& functionName) {
101                 std::vector<std::shared_ptr<T> > plugins;
102 
103                 QueryInterface<T, D>(
104                     functionName,
105                     [&plugins](
106                         musik::core::sdk::IPlugin* unused,
107                         std::shared_ptr<T> plugin,
108                         const std::string& fn)
109                         {
110                             plugins.push_back(plugin);
111                         });
112 
113                 return plugins;
114             }
115 
QueryFunction(const std::string & functionName,std::function<void (musik::core::sdk::IPlugin *,T)> handler)116             template <class T> void QueryFunction(
117                 const std::string& functionName,
118                 std::function<void(musik::core::sdk::IPlugin*, T)> handler)
119             {
120                 std::unique_lock<std::mutex> lock(this->mutex);
121 
122                 for (std::shared_ptr<Descriptor> descriptor : this->plugins) {
123                     if (prefs->GetBool(descriptor->key.c_str(), true)) { /* if enabled by prefs */
124                         T funcPtr =
125 #ifdef WIN32
126                             (T) GetProcAddress((HMODULE)(descriptor->nativeHandle), functionName.c_str());
127 #else
128                             (T)dlsym(descriptor->nativeHandle, functionName.c_str());
129 #endif
130                         if (funcPtr) {
131                             handler(descriptor->plugin, funcPtr);
132                         }
133                     }
134                 }
135             }
136 
QueryGuid(const std::string & guid)137             std::shared_ptr<musik::core::sdk::IPlugin> QueryGuid(const std::string& guid) {
138                 using T = musik::core::sdk::IPlugin;
139                 std::shared_ptr<T> result;
140                 using Deleter = PluginFactory::ReleaseDeleter<T>;
141                 Instance().QueryInterface<T, Deleter>(
142                     "GetPlugin",
143                     [&result, guid](T* unused, std::shared_ptr<T> plugin, const std::string& fn) {
144                         if (std::string(plugin->Guid()) == guid) {
145                             result = plugin;
146                         }
147                     });
148                 return result;
149             }
150 
151         private:
152             struct Descriptor {
153                 musik::core::sdk::IPlugin* plugin;
154                 void* nativeHandle;
155                 std::string filename;
156                 std::string key;
157             };
158 
159             PluginFactory();
160             ~PluginFactory();
161             void LoadPlugins();
162 
163             std::vector<std::shared_ptr<Descriptor> > plugins;
164             std::mutex mutex;
165             std::shared_ptr<musik::core::sdk::IPreferences> prefs;
166     };
167 } }
168