1 /*
2 
3 Boost Software License - Version 1.0 - August 17th, 2003
4 
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license ( the "Software" ) to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 
27 */
28 module derelict.util.loader;
29 
30 private {
31 	import std.array : split;
32 	import std.string : strip;
33 
34     import derelict.util.sharedlib;
35     import derelict.util.exception;
36 }
37 
38 struct SharedLibVersion {
39     int major;
40     int minor;
41     int patch;
42 }
43 
44 abstract class SharedLibLoader {
45     private {
46         string _libNames;
47         SharedLib _lib;
48     }
49 
50     /++
51      Constructs a new instance of shared lib loader with a string of one
52      or more shared library names to use as default.
53 
54      Params:
55         libNames =      A string containing one or more comma-separated shared
56                         library names.
57     +/
58     public this( string libNames ) {
59         _libNames = libNames;
60     }
61 
62     public final {
63         /++
64          Finds and loads a shared library, using this loader's default shared library
65          names and default supported shared library version.
66 
67          If multiple library names are specified as default, a SharedLibLoadException
68          will only be thrown if all of the libraries fail to load. It will be the head
69          of an exceptin chain containing one instance of the exception for each library
70          that failed.
71 
72          Examples:  If this loader supports versions 2.0 and 2.1 of a shared libary,
73                     this method will attempt to load 2.1 and will fail if only 2.0
74                     is present on the system.
75 
76          Throws:    SharedLibLoadException if the shared library or one of its
77                     dependencies cannot be found on the file system.
78                     SymbolLoadException if an expected symbol is missing from the
79                     library.
80         +/
81         void load() {
82             load( _libNames );
83         }
84 
85         /++
86          Finds and loads any version of a shared library greater than or equal to
87          the required mimimum version, using this loader's default shared library
88          names.
89 
90          If multiple library names are specified as default, a SharedLibLoadException
91          will only be thrown if all of the libraries fail to load. It will be the head
92          of an exceptin chain containing one instance of the exception for each library
93          that failed.
94 
95          Examples:  If this loader supports versions 2.0 and 2.1 of a shared library,
96                     passing a SharedLibVersion with the major field set to 2 and the
97                     minor field set to 0 will cause the loader to load version 2.0
98                     if version 2.1 is not available on the system.
99 
100          Params:
101             minRequiredVersion = the minimum version of the library that is acceptable.
102                                  Subclasses are free to ignore this.
103 
104          Throws:    SharedLibLoadException if the shared library or one of its
105                     dependencies cannot be found on the file system.
106                     SymbolLoadException if an expected symbol is missing from the
107                     library.
108         +/
109         void load( SharedLibVersion minRequiredVersion ) {
110             configureMinimumVersion( minRequiredVersion );
111             load();
112         }
113 
114         /++
115          Finds and loads a shared library, using libNames to find the library
116          on the file system.
117 
118          If multiple library names are specified in libNames, a SharedLibLoadException
119          will only be thrown if all of the libraries fail to load. It will be the head
120          of an exceptin chain containing one instance of the exception for each library
121          that failed.
122 
123          Examples:  If this loader supports versions 2.0 and 2.1 of a shared libary,
124                     this method will attempt to load 2.1 and will fail if only 2.0
125                     is present on the system.
126 
127          Params:
128             libNames =      A string containing one or more comma-separated shared
129                             library names.
130          Throws:    SharedLibLoadException if the shared library or one of its
131                     dependencies cannot be found on the file system.
132                     SymbolLoadException if an expected symbol is missing from the
133                     library.
134         +/
135         void load( string libNames ) {
136             assert( libNames !is null );
137 
138             auto lnames = libNames.split( "," );
139             foreach( ref string l; lnames )
140                 l = l.strip();
141 
142             load( lnames );
143         }
144 
145         /++
146          Finds and loads any version of a shared library greater than or equal to
147          the required mimimum version, using libNames to find the library
148          on the file system.
149 
150          If multiple library names are specified as default, a SharedLibLoadException
151          will only be thrown if all of the libraries fail to load. It will be the head
152          of an exceptin chain containing one instance of the exception for each library
153          that failed.
154 
155          Examples:  If this loader supports versions 2.0 and 2.1 of a shared library,
156                     passing a SharedLibVersion with the major field set to 2 and the
157                     minor field set to 0 will cause the loader to load version 2.0
158                     if version 2.1 is not available on the system.
159 
160          Params:
161             libNames =      A string containing one or more comma-separated shared
162                             library names.
163             minRequiredVersion = The minimum version of the library that is acceptable.
164                                  Subclasses are free to ignore this.
165 
166          Throws:    SharedLibLoadException if the shared library or one of its
167                     dependencies cannot be found on the file system.
168                     SymbolLoadException if an expected symbol is missing from the
169                     library.
170         +/
171         void load( string libNames, SharedLibVersion minRequiredVersion ) {
172             configureMinimumVersion( minRequiredVersion );
173             load( libNames );
174         }
175 
176         /++
177          Finds and loads a shared library, using libNames to find the library
178          on the file system.
179 
180          If multiple library names are specified in libNames, a SharedLibLoadException
181          will only be thrown if all of the libraries fail to load. It will be the head
182          of an exceptin chain containing one instance of the exception for each library
183          that failed.
184 
185 
186          Params:
187             libNames =      An array containing one or more shared library names,
188                             with one name per index.
189 
190          Throws:    SharedLibLoadException if the shared library or one of its
191                     dependencies cannot be found on the file system.
192                     SymbolLoadException if an expected symbol is missing from the
193                     library.
194         +/
195         void load( string[] libNames ) {
196             _lib.load( libNames );
197             loadSymbols();
198         }
199 
200         /++
201          Finds and loads any version of a shared library greater than or equal to
202          the required mimimum version, , using libNames to find the library
203          on the file system.
204 
205          If multiple library names are specified in libNames, a SharedLibLoadException
206          will only be thrown if all of the libraries fail to load. It will be the head
207          of an exceptin chain containing one instance of the exception for each library
208          that failed.
209 
210          Examples:  If this loader supports versions 2.0 and 2.1 of a shared library,
211                     passing a SharedLibVersion with the major field set to 2 and the
212                     minor field set to 0 will cause the loader to load version 2.0
213                     if version 2.1 is not available on the system.
214 
215 
216          Params:
217             libNames =      An array containing one or more shared library names,
218                             with one name per index.
219             minRequiredVersion = The minimum version of the library that is acceptable.
220                                  Subclasses are free to ignore this.
221 
222          Throws:    SharedLibLoadException if the shared library or one of its
223                     dependencies cannot be found on the file system.
224                     SymbolLoadException if an expected symbol is missing from the
225                     library.
226         +/
227         void load( string[] libNames, SharedLibVersion minRequiredVersion ) {
228             configureMinimumVersion( minRequiredVersion );
229             load( libNames );
230         }
231 
232         /++
233          Unloads the shared library from memory, invalidating all function pointers
234          which were assigned a symbol by one of the load methods.
235         +/
236         void unload() {
237             _lib.unload();
238         }
239 
240         @property {
241             /// Returns: true if the shared library is loaded, false otherwise.
242             bool isLoaded() {
243                 return _lib.isLoaded;
244             }
245 
246             /++
247              Sets the callback that will be called when an expected symbol is
248              missing from the shared library.
249 
250              Params:
251                 callback =      A delegate that returns a value of type
252                                 derelict.util.exception.ShouldThrow and accepts
253                                 a string as the sole parameter.
254             +/
255             void missingSymbolCallback( MissingSymbolCallbackDg callback ) {
256                 _lib.missingSymbolCallback = callback;
257             }
258 
259             /++
260              Sets the callback that will be called when an expected symbol is
261              missing from the shared library.
262 
263              Params:
264                 callback =      A pointer to a function that returns a value of type
265                                 derelict.util.exception.ShouldThrow and accepts
266                                 a string as the sole parameter.
267             +/
268             void missingSymbolCallback( MissingSymbolCallbackFunc callback ) {
269                 _lib.missingSymbolCallback = callback;
270             }
271         }
272     }
273 
274     protected {
275         /++
276          Must be implemented by subclasses to load all of the symbols from a
277          shared library.
278 
279          This method is called by the load methods.
280         +/
281         abstract void loadSymbols();
282 
283         /++
284          Allows a subclass to install an exception handler for specific versions
285          of a library before loadSymbols is called.
286 
287          This method is optional. The default implementation does nothing.
288         +/
289         void configureMinimumVersion( SharedLibVersion minVersion ) {}
290 
291         /++
292          Subclasses can use this as an alternative to bindFunc, but must bind
293          the returned symbol manually.
294 
295          Params:
296             name =      The name of the symbol to load.doThrow =   If true, a SymbolLoadException will be thrown if the symbol
297                         is missing. If false, no exception will be thrown and the
298                         ptr parameter will be set to null.
299          Throws:        SymbolLoadException if doThrow is true and a the symbol
300                         specified by funcName is missing from the shared library.
301          Returns:       The symbol matching the name parameter.
302         +/
303         void* loadSymbol( string name, bool doThrow = true ) {
304             return _lib.loadSymbol( name, doThrow );
305         }
306 
307         /// Returns a reference to the shared library wrapped by this loader.
308         final ref SharedLib lib() @property {
309             return _lib;
310         }
311 
312         /++
313          Subclasses can use this to bind a function pointer to a symbol in the
314          shared library.
315 
316          Params:
317             ptr =       Pointer to a function pointer that will be used as the bind
318                         point.
319             funcName =  The name of the symbol to be bound.
320             doThrow =   If true, a SymbolLoadException will be thrown if the symbol
321                         is missing. If false, no exception will be thrown and the
322                         ptr parameter will be set to null.
323          Throws:        SymbolLoadException if doThrow is true and a the symbol
324                         specified by funcName is missing from the shared library.
325         +/
326         final void bindFunc( void** ptr, string funcName, bool doThrow = true ) {
327             void* func = _lib.loadSymbol( funcName, doThrow );
328             *ptr = func;
329         }
330     }
331 }