case insensitive VST plugin file extension - fixes #6285
[ardour.git] / libs / ardour / plugin_manager.cc
index 5c809c213bbfd61efd02ea357797a33700d3bc24..37eb61ef3b88ea4d787517f057205fba85c8a707 100644 (file)
@@ -49,6 +49,8 @@
 #include <glib/gstdio.h>
 #include <glibmm/miscutils.h>
 #include <glibmm/pattern.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
 
 #include "pbd/whitespace.h"
 #include "pbd/file_utils.h"
@@ -115,10 +117,36 @@ PluginManager::PluginManager ()
        char* s;
        string lrdf_path;
 
-       string  scan_p = Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst");
-       if (!PBD::find_file_in_search_path ( PBD::Searchpath(scan_p), "ardour-vst-scanner", scanner_bin_path)) {
-               PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << scan_p <<  endmsg;
+#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT
+       // source-tree (ardev, etc)
+       PBD::Searchpath vstsp(Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst"));
+
+#ifdef PLATFORM_WINDOWS
+       // on windows the .exe needs to be in the same folder with libardour.dll
+       vstsp += Glib::build_filename(g_win32_get_package_installation_directory_of_module (0), "bin");
+#else
+       // on Unices additional internal-use binaries are deployed to $libdir
+       vstsp += ARDOUR::ardour_dll_directory();
+#endif
+
+       if (!PBD::find_file (vstsp,
+#ifdef PLATFORM_WINDOWS
+    #ifdef DEBUGGABLE_SCANNER_APP
+        #if defined(DEBUG) || defined(_DEBUG)
+                               "ardour-vst-scannerD.exe"
+        #else
+                               "ardour-vst-scannerRDC.exe"
+        #endif
+    #else
+                               "ardour-vst-scanner.exe"
+    #endif
+#else
+                               "ardour-vst-scanner"
+#endif
+                               , scanner_bin_path)) {
+               PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << vstsp.to_string() <<  endmsg;
        }
+#endif
 
        load_statuses ();
 
@@ -184,6 +212,14 @@ PluginManager::PluginManager ()
 
 PluginManager::~PluginManager()
 {
+       if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
+               // don't bother, just exit quickly.
+               delete _windows_vst_plugin_info;
+               delete _lxvst_plugin_info;
+               delete _ladspa_plugin_info;
+               delete _lv2_plugin_info;
+               delete _au_plugin_info;
+       }
 }
 
 void
@@ -214,7 +250,7 @@ PluginManager::refresh (bool cache_only)
 
 #ifdef AUDIOUNIT_SUPPORT
        BootMessage (_("Scanning AU Plugins"));
-       au_refresh ();
+       au_refresh (cache_only);
 #endif
 
        BootMessage (_("Plugin Scan Complete..."));
@@ -242,7 +278,7 @@ PluginManager::clear_vst_cache ()
 #ifdef WINDOWS_VST_SUPPORT
        {
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$");
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$", true);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -252,7 +288,7 @@ PluginManager::clear_vst_cache ()
 #ifdef LXVST_SUPPORT
        {
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$");
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$", true);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -263,7 +299,7 @@ PluginManager::clear_vst_cache ()
        {
                string personal = get_personal_vst_info_cache_dir();
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, personal, "\\.fsi$");
+               find_files_matching_regex (fsi_files, personal, "\\.fsi$", /* user cache is flat, no recursion */ false);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -277,7 +313,7 @@ PluginManager::clear_vst_blacklist ()
 #ifdef WINDOWS_VST_SUPPORT
        {
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsb$");
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsb$", true);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -287,7 +323,7 @@ PluginManager::clear_vst_blacklist ()
 #ifdef LXVST_SUPPORT
        {
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsb$");
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsb$", true);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -299,7 +335,7 @@ PluginManager::clear_vst_blacklist ()
                string personal = get_personal_vst_blacklist_dir();
 
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, personal, "\\.fsb$");
+               find_files_matching_regex (fsi_files, personal, "\\.fsb$", /* flat user cache */ false);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -307,6 +343,29 @@ PluginManager::clear_vst_blacklist ()
 #endif
 }
 
+void
+PluginManager::clear_au_cache ()
+{
+#ifdef AUDIOUNIT_SUPPORT
+       // AUPluginInfo::au_cache_path ()
+       string fn = Glib::build_filename (ARDOUR::user_config_directory(), "au_cache");
+       if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
+               ::g_unlink(fn.c_str());
+       }
+#endif
+}
+
+void
+PluginManager::clear_au_blacklist ()
+{
+#ifdef AUDIOUNIT_SUPPORT
+       string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
+       if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
+               ::g_unlink(fn.c_str());
+       }
+#endif
+}
+
 void
 PluginManager::ladspa_refresh ()
 {
@@ -336,6 +395,7 @@ PluginManager::ladspa_refresh ()
        }
 }
 
+#ifdef HAVE_LRDF
 static bool rdf_filter (const string &str, void* /*arg*/)
 {
        return str[0] != '.' &&
@@ -344,6 +404,7 @@ static bool rdf_filter (const string &str, void* /*arg*/)
                    (str.find(".n3")   == (str.length() - 3)) ||
                    (str.find(".ttl")  == (str.length() - 4)));
 }
+#endif
 
 void
 PluginManager::add_ladspa_presets()
@@ -575,11 +636,35 @@ PluginManager::lv2_refresh ()
 
 #ifdef AUDIOUNIT_SUPPORT
 void
-PluginManager::au_refresh ()
+PluginManager::au_refresh (bool cache_only)
 {
        DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
+       if (cache_only && !Config->get_discover_audio_units ()) {
+               return;
+       }
        delete _au_plugin_info;
        _au_plugin_info = AUPluginInfo::discover();
+
+       // disable automatic scan in case we crash
+       Config->set_discover_audio_units (false);
+       Config->save_state();
+
+       /* note: AU require a CAComponentDescription pointer provided by the OS.
+        * Ardour only caches port and i/o config. It can't just 'scan' without
+        * 'discovering' (like we do for VST).
+        *
+        * So in case discovery fails, we assume the worst: the Description
+        * is broken (malicious plugins) and even a simple 'scan' would always
+        * crash ardour on startup. Hence we disable Auto-Scan on start.
+        *
+        * If the crash happens at any later time (description is available),
+        * Ardour will blacklist the plugin in question -- unless
+        * the crash happens during realtime-run.
+        */
+
+       // successful scan re-enabled automatic discovery
+       Config->set_discover_audio_units (true);
+       Config->save_state();
 }
 
 #endif
@@ -601,8 +686,7 @@ PluginManager::windows_vst_refresh (bool cache_only)
 static bool windows_vst_filter (const string& str, void * /*arg*/)
 {
        /* Not a dotfile, has a prefix before a period, suffix is "dll" */
-
-       return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
+       return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4));
 }
 
 int
@@ -614,7 +698,7 @@ PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
 
        DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
 
-       find_files_matching_filter (plugin_objects, Config->get_plugin_path_vst(), windows_vst_filter, 0, false, true);
+       find_files_matching_filter (plugin_objects, Config->get_plugin_path_vst(), windows_vst_filter, 0, false, true, true);
 
        for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
                ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled());
@@ -733,7 +817,7 @@ PluginManager::lxvst_discover_from_path (string path, bool cache_only)
 
        DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
 
-       find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true);
+       find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
 
        for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
                ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
@@ -1021,9 +1105,9 @@ ARDOUR::PluginInfoList&
 PluginManager::au_plugin_info ()
 {
 #ifdef AUDIOUNIT_SUPPORT
-       assert(_au_plugin_info);
-       return *_au_plugin_info;
-#else
-       return _empty_plugin_info;
+       if (_au_plugin_info) {
+               return *_au_plugin_info;
+       }
 #endif
+       return _empty_plugin_info;
 }