openfx-sys 0.1.0

Rust bindings for OpenFX
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
#ifndef OFX_PLUGIN_CACHE_H
#define OFX_PLUGIN_CACHE_H

/*
Software License :

Copyright (c) 2007-2009, The Open Effects Association Ltd.  All Rights Reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name The Open Effects Association Ltd, nor the names of its 
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <string>
#include <vector>
#include <list>
#include <set>
#include <iostream>

#include <stdio.h>

#include "expat.h"

#include "ofxCore.h"
#include "ofxhPropertySuite.h"
#include "ofxhPluginAPICache.h"
#include "ofxhBinary.h"

namespace OFX {

  namespace Host {

    class Host;

    // forward delcarations
    class PluginDesc;   
    class Plugin;
    class PluginBinary;
    class PluginCache;

    /// C++ version of the information kept inside an OfxPlugin struct
    class PluginDesc  {
    protected :
      std::string _pluginApi;  ///< the API I implement
      int _apiVersion;         ///< the version of the API

      std::string _identifier; ///< the identifier of the plugin
      std::string _rawIdentifier; ///< the original identifier of the plugin
      int _versionMajor;       ///< the plugin major version
      int _versionMinor;       ///< the plugin minor version

    public:

      const std::string &getPluginApi() const {
        return _pluginApi;
      }
      
      int getApiVersion() const {
        return _apiVersion;
      }
      
      const std::string &getIdentifier() const {
        return _identifier;
      }

      const std::string &getRawIdentifier() const {
        return _rawIdentifier;
      }
      
      int getVersionMajor() const {
        return _versionMajor;
      }
      
      int getVersionMinor() const  {
        return _versionMinor;
      }

      PluginDesc() : _apiVersion(-1) {
      }

      virtual ~PluginDesc() {}

      PluginDesc(const std::string &api,
                 int apiVersion,
                 const std::string &identifier,
                 const std::string &rawIdentifier,
                 int versionMajor,
                 int versionMinor)
        : _pluginApi(api)
        , _apiVersion(apiVersion)
        , _identifier(identifier)
        , _rawIdentifier(rawIdentifier)
        , _versionMajor(versionMajor)
        , _versionMinor(versionMinor)
      {
      }


      /// constructor for the case where we have already loaded the plugin binary and 
      /// are populating this object from it
      PluginDesc(OfxPlugin *ofxPlugin) {
        _pluginApi = ofxPlugin->pluginApi;
        _apiVersion = ofxPlugin->apiVersion;
        _rawIdentifier = ofxPlugin->pluginIdentifier;
        _identifier = ofxPlugin->pluginIdentifier;

        // Who says the pluginIdentifier is case-insensitive? OFX 1.3 spec doesn't mention this.
        // http://openfx.sourceforge.net/Documentation/1.3/ofxProgrammingReference.html#id472588
        //for (size_t i=0;i<_identifier.size();i++) {
        //  _identifier[i] = tolower(_identifier[i]);
        //}
        _versionMajor = ofxPlugin->pluginVersionMajor;
        _versionMinor = ofxPlugin->pluginVersionMinor;
      }

    };
    
    /// class that we use to manipulate a plugin
    class Plugin : public PluginDesc {
    /// owned by the PluginBinary it lives inside
    /// Plugins can only be pass about either by pointer or reference
    private :
      Plugin(const Plugin&) : PluginDesc() {}                          ///< hidden
      Plugin &operator= (const Plugin&) {return *this;} ///< hidden

    protected :
      PluginBinary *_binary; ///< the file I live inside
      int           _index;  ///< where I live inside that file
    public :
      Plugin();

      PluginBinary *getBinary()
      {
        return _binary;
      }

      const PluginBinary *getBinary() const
      {
        return _binary;
      }

      int getIndex() const
      {
        return _index;
      }

      /// construct this based on the struct returned by the getNthPlugin() in the binary
      Plugin(PluginBinary *bin, int idx, OfxPlugin *o) : PluginDesc(o), _binary(bin), _index(idx)
      {
      }
      
      /// construct me from the cache
      Plugin(PluginBinary *bin, int idx, const std::string &api,
             int apiVersion, const std::string &identifier, 
             const std::string &rawIdentifier,
             int majorVersion, int minorVersion)
        : PluginDesc(api, apiVersion, identifier, rawIdentifier, majorVersion, minorVersion)
        , _binary(bin)
        , _index(idx) 
      {
      }

      virtual ~Plugin() {
      }

      virtual APICache::PluginAPICacheI &getApiHandler() = 0;

      bool trumps(Plugin *other) {
        int myMajor = getVersionMajor();
        int theirMajor = other->getVersionMajor();

        int myMinor = getVersionMinor();
        int theirMinor = other->getVersionMinor();

        if (myMajor > theirMajor) {
          return true;
        }
        
        if (myMajor == theirMajor && myMinor > theirMinor) {
          return true;
        }

        return false;
      }
    };

    class PluginHandle;

    /// class that represents a binary file which holds plugins
    class PluginBinary {
    /// has a set of plugins inside it and which it owns
    /// These are owned by a PluginCache
      friend class PluginHandle;

    protected :
      Binary _binary;                 ///< our binary object, abstracted layer ontop of OS calls, defined in ofxhBinary.h
      std::string _filePath;          ///< full path to the file
      std::string _bundlePath;        ///< path to the .bundle directory
      std::vector<Plugin *> _plugins; ///< my plugins
      time_t _fileModificationTime;   ///< used as a time stamp to check modification times, used for caching
      off_t _fileSize;                ///< file size last time we check, used for caching
      bool _binaryChanged;            ///< whether the timestamp/filesize in this cache is different from that in the actual binary
      
    public :

      /// create one from the cache.  this will invoke the Binary() constructor which
      /// will stat() the file.
      explicit PluginBinary(const std::string &file, const std::string &bundlePath, time_t mtime, off_t size)
        : _binary(file)
        , _filePath(file)
        , _bundlePath(bundlePath)
        , _fileModificationTime(mtime)
        , _fileSize(size)
        , _binaryChanged(false)
      {
        if (isInvalid()) {
          return;
        }
        if (_fileModificationTime != _binary.getTime() || _fileSize != _binary.getSize()) {
          _binaryChanged = true;
        }
      }


      /// constructor which will open a library file, call things inside it, and then 
      /// create Plugin objects as appropriate for the plugins exported therefrom
      explicit PluginBinary(const std::string &file, const std::string &bundlePath, PluginCache *cache)
        : _binary(file)
        , _filePath(file)
        , _bundlePath(bundlePath)
        , _binaryChanged(false)
      {
        loadPluginInfo(cache);
      }
    
      /// dtor
      virtual ~PluginBinary();


      time_t getFileModificationTime() const {
      	return _fileModificationTime;
      }
    
      off_t getFileSize() {
      	return _fileSize;
      }

      const std::string &getFilePath() const {
        return _filePath;
      }
      
      const std::string &getBundlePath() const {
        return _bundlePath;
      }
      
      bool hasBinaryChanged() const {
        return _binaryChanged;
      }

      bool isLoaded() const {
        return _binary.isLoaded();
      }
        
      bool isInvalid() const {
        return _binary.isInvalid();
      }

      void addPlugin(Plugin *pe) {
        _plugins.push_back(pe);
      }

      void loadPluginInfo(PluginCache *);

      /// how many plugins?
      int getNPlugins() const {return (int)_plugins.size(); }

      /// get a plugin 
      Plugin &getPlugin(int idx) {return *_plugins[idx];}

      /// get a plugin 
      const Plugin &getPlugin(int idx) const {return *_plugins[idx];}
    };

    /// wrapper class for Plugin/PluginBinary.  use in a RAIA fashion to make sure the binary gets unloaded when needed and not before.
    class PluginHandle {
      PluginBinary *_b;
      OfxPlugin *_op;

    public:
      PluginHandle(Plugin *p, OFX::Host::Host *_host);
      virtual ~PluginHandle();

      OfxPlugin *getOfxPlugin() {
        return _op;
      }

      OfxPlugin *operator->() {
        return _op;
      }
    };
    
    /// for later 
    struct PluginCacheSupportedApi {
      std::string api;
      int minVersion;
      int maxVersion;
      APICache::PluginAPICacheI *handler;

      PluginCacheSupportedApi(const std::string &_api, int _minVersion, int _maxVersion, APICache::PluginAPICacheI *_handler) :
        api(_api), minVersion(_minVersion), maxVersion(_maxVersion), handler(_handler)
      {
      }
      
      bool matches(const std::string &_api, int _version) const
      {
        if (_api == api && _version >= minVersion && _version <= maxVersion) {
          return true;
        }
        return false;
      }
    };

    /// Where we keep our plugins.    
    class PluginCache {
    protected :
      OFX::Host::Property::PropSpec* _hostSpec;

      std::list<std::string>    _pluginPath;  ///< list of directories to look in
      std::set<std::string>     _nonrecursePath; ///< list of directories to look in (non-recursively)
      std::list<std::string>    _pluginDirs;  ///< list of directories we found
      std::list<PluginBinary *> _binaries; ///< all the binaries we know about, we own these
      std::list<Plugin *>       _plugins;  ///< all the plugins inside the binaries, we don't own these, populated from _binaries
      std::set<std::string>     _knownBinFiles;

      PluginBinary *_xmlCurrentBinary;
      Plugin *_xmlCurrentPlugin;

      std::list<PluginCacheSupportedApi> _apiHandlers;

      void scanDirectory(std::set<std::string> &foundBinFiles, const std::string &dir, bool recurse);

      bool _ignoreCache;
      std::string _cacheVersion;

      bool _dirty;
      bool _enablePluginSeek;       ///< Turn off to make all seekPluginFile() calls return an empty string

      static PluginCache* gPluginCachePtr; ///< singleton plugin cache

    public:
      /// ctor, which inits _pluginPath to default locations and not much else
      PluginCache();

      /// dtor
      ~PluginCache();

      /// get our plugin cache
      static PluginCache* getPluginCache();

      /// clear our plugin cache
      static void clearPluginCache();		

      /// get the list in which plugins are sought
      const std::list<std::string> &getPluginPath() {
        return _pluginPath;
      }

      /// was the cache outdated?
      bool dirty() const {
        return _dirty;
      }

      /// add a file to the plugin path
      void addFileToPath(const std::string &f, bool recurse=true) {
        _pluginPath.push_back(f);
        if (!recurse) {
          _nonrecursePath.insert(f);
        }
      }

      /// prepend a file to the plugin path
      void prependFileToPath(const std::string &f, bool recurse=true) {
        _pluginPath.push_front(f);
        if (!recurse) {
          _nonrecursePath.insert(f);
        }
      }

      /// specify which subdirectory of /usr/OFX or equivilant
      /// (as well as 'Plugins') to look in for plugins.
      void setPluginHostPath(const std::string &hostId);

      /// set the version string to write to the cache, 
      /// and also that we expect on cachess read in
      void setCacheVersion(const std::string &cacheVersion) {
        _cacheVersion = cacheVersion;
      }

      // populate the cache.  must call scanPluginFiles() after to check for changes.
      void readCache(std::istream &is);

      // seek a particular file on the OFX plugin path
      std::string seekPluginFile(const std::string &baseName) const;
      
      /// Sets behaviour of seekPluginFile().
      /// Enable (the default): normal operation; disable: returns an empty string instead
      void setPluginSeekEnabled(bool enabled) { _enablePluginSeek = enabled; }

      /// scan for plugins
      void scanPluginFiles();

      // write the plugin cache output file to the given stream
      void writePluginCache(std::ostream &os) const;
      
      // callback function for the XML
      void elementBeginCallback(void *userData, const XML_Char *name, const XML_Char **attrs);
      void elementCharCallback(void *userData, const XML_Char *data, int len);
      void elementEndCallback(void *userData, const XML_Char *name);

      /// register an API cache handler
      void registerAPICache(const std::string &api, int min, int max, APICache::PluginAPICacheI *apiCache) {
        _apiHandlers.push_back(PluginCacheSupportedApi(api, min, max, apiCache));
      }
      
      /// find the API cache handler for the given api/apiverson
      APICache::PluginAPICacheI* findApiHandler(const std::string &api, int apiver);

      /// obtain a list of plugins to walk through
      const std::list<Plugin *> &getPlugins() const {
        return _plugins;
      }
    };

  }
}

#endif