Chris@4: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@5: /* Chris@35: Copyright (c) 2016-2018 Queen Mary, University of London Chris@5: Chris@20: Permission is hereby granted, free of charge, to any person Chris@20: obtaining a copy of this software and associated documentation Chris@20: files (the "Software"), to deal in the Software without Chris@20: restriction, including without limitation the rights to use, copy, Chris@20: modify, merge, publish, distribute, sublicense, and/or sell copies Chris@20: of the Software, and to permit persons to whom the Software is Chris@20: furnished to do so, subject to the following conditions: Chris@5: Chris@20: The above copyright notice and this permission notice shall be Chris@20: included in all copies or substantial portions of the Software. Chris@5: Chris@20: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Chris@20: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF Chris@20: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND Chris@20: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY Chris@20: CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF Chris@20: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION Chris@20: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Chris@5: Chris@20: Except as contained in this notice, the names of the Centre for Chris@20: Digital Music and Queen Mary, University of London shall not be Chris@20: used in advertising or otherwise to promote the sale, use or other Chris@20: dealings in this Software without prior written authorization. Chris@5: */ Chris@4: Chris@4: #include "knownplugins.h" Chris@4: Chris@36: #include Chris@36: Chris@4: using namespace std; Chris@4: Chris@4: #if defined(_WIN32) Chris@36: #include Chris@4: #define PATH_SEPARATOR ';' Chris@4: #else Chris@4: #define PATH_SEPARATOR ':' Chris@4: #endif Chris@4: Chris@36: static bool Chris@36: getEnvUtf8(std::string variable, std::string &value) Chris@36: { Chris@36: value = ""; Chris@36: Chris@36: #ifdef _WIN32 Chris@36: int wvarlen = MultiByteToWideChar(CP_UTF8, 0, Chris@36: variable.c_str(), int(variable.length()), Chris@36: 0, 0); Chris@36: if (wvarlen < 0) { Chris@36: cerr << "WARNING: Unable to convert environment variable name " Chris@36: << variable << " to wide characters" << endl; Chris@36: return false; Chris@36: } Chris@36: Chris@36: wchar_t *wvarbuf = new wchar_t[wvarlen + 1]; Chris@36: (void)MultiByteToWideChar(CP_UTF8, 0, Chris@36: variable.c_str(), int(variable.length()), Chris@36: wvarbuf, wvarlen); Chris@36: wvarbuf[wvarlen] = L'\0'; Chris@36: Chris@36: wchar_t *wvalue = _wgetenv(wvarbuf); Chris@36: Chris@36: delete[] wvarbuf; Chris@36: Chris@36: if (!wvalue) { Chris@36: return false; Chris@36: } Chris@36: Chris@36: int wvallen = int(wcslen(wvalue)); Chris@36: int vallen = WideCharToMultiByte(CP_UTF8, 0, Chris@36: wvalue, wvallen, Chris@36: 0, 0, 0, 0); Chris@36: if (vallen < 0) { Chris@36: cerr << "WARNING: Unable to convert environment value to UTF-8" << endl; Chris@36: return false; Chris@36: } Chris@36: Chris@36: char *val = new char[vallen + 1]; Chris@36: (void)WideCharToMultiByte(CP_UTF8, 0, Chris@36: wvalue, wvallen, Chris@36: val, vallen, 0, 0); Chris@36: val[vallen] = '\0'; Chris@36: Chris@36: value = val; Chris@36: Chris@36: delete[] val; Chris@36: return true; Chris@36: Chris@36: #else Chris@36: Chris@36: char *val = getenv(variable.c_str()); Chris@36: if (!val) { Chris@36: return false; Chris@36: } Chris@36: Chris@36: value = val; Chris@36: return true; Chris@36: Chris@36: #endif Chris@36: } Chris@36: Chris@35: KnownPlugins::KnownPlugins(BinaryFormat format) : Chris@35: m_format(format) Chris@4: { Chris@35: string variableSuffix = ""; Chris@35: if (m_format == FormatNonNative32Bit) { Chris@34: variableSuffix = "_32"; Chris@34: } Chris@6: Chris@34: m_known[VampPlugin] = { Chris@34: "vamp", Chris@34: "VAMP_PATH" + variableSuffix, Chris@35: {}, {}, Chris@34: "vampGetPluginDescriptor" Chris@34: }; Chris@34: Chris@34: m_known[LADSPAPlugin] = { Chris@34: "ladspa", Chris@34: "LADSPA_PATH" + variableSuffix, Chris@35: {}, {}, Chris@34: "ladspa_descriptor" Chris@34: }; Chris@34: Chris@34: m_known[DSSIPlugin] = { Chris@34: "dssi", Chris@34: "DSSI_PATH" + variableSuffix, Chris@35: {}, {}, Chris@34: "dssi_descriptor" Chris@4: }; Chris@4: Chris@35: for (auto &k: m_known) { Chris@35: k.second.defaultPath = expandPathString(getDefaultPathString(k.first)); Chris@35: k.second.path = expandConventionalPath(k.first, k.second.variable); Chris@4: } Chris@4: } Chris@4: Chris@35: vector Chris@34: KnownPlugins::getKnownPluginTypes() const Chris@34: { Chris@35: vector kt; Chris@34: Chris@34: for (const auto &k: m_known) { Chris@34: kt.push_back(k.first); Chris@34: } Chris@34: Chris@34: return kt; Chris@34: } Chris@34: Chris@4: string Chris@35: KnownPlugins::getUnexpandedDefaultPathString(PluginType type) Chris@4: { Chris@4: switch (type) { Chris@4: Chris@4: #if defined(_WIN32) Chris@4: Chris@4: case VampPlugin: Chris@19: return "%ProgramFiles%\\Vamp Plugins"; Chris@4: case LADSPAPlugin: Chris@19: return "%ProgramFiles%\\LADSPA Plugins;%ProgramFiles%\\Audacity\\Plug-Ins"; Chris@4: case DSSIPlugin: Chris@19: return "%ProgramFiles%\\DSSI Plugins"; Chris@19: Chris@4: #elif defined(__APPLE__) Chris@19: Chris@4: case VampPlugin: Chris@19: return "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"; Chris@4: case LADSPAPlugin: Chris@19: return "$HOME/Library/Audio/Plug-Ins/LADSPA:/Library/Audio/Plug-Ins/LADSPA"; Chris@4: case DSSIPlugin: Chris@19: return "$HOME/Library/Audio/Plug-Ins/DSSI:/Library/Audio/Plug-Ins/DSSI"; Chris@19: Chris@4: #else /* Linux, BSDs, etc */ Chris@19: Chris@4: case VampPlugin: Chris@19: return "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"; Chris@4: case LADSPAPlugin: Chris@19: return "$HOME/ladspa:$HOME/.ladspa:/usr/local/lib/ladspa:/usr/lib/ladspa"; Chris@4: case DSSIPlugin: Chris@19: return "$HOME/dssi:$HOME/.dssi:/usr/local/lib/dssi:/usr/lib/dssi"; Chris@4: #endif Chris@4: } Chris@4: Chris@4: throw logic_error("unknown or unhandled plugin type"); Chris@4: } Chris@4: Chris@35: string Chris@35: KnownPlugins::getDefaultPathString(PluginType type) Chris@35: { Chris@35: string path = getUnexpandedDefaultPathString(type); Chris@35: Chris@35: if (path == "") { Chris@35: return path; Chris@35: } Chris@35: Chris@36: string home; Chris@36: if (getEnvUtf8("HOME", home)) { Chris@35: string::size_type f; Chris@35: while ((f = path.find("$HOME")) != string::npos && Chris@35: f < path.length()) { Chris@35: path.replace(f, 5, home); Chris@35: } Chris@35: } Chris@35: Chris@35: #ifdef _WIN32 Chris@36: string pfiles, pfiles32; Chris@36: if (!getEnvUtf8("ProgramFiles", pfiles)) { Chris@35: pfiles = "C:\\Program Files"; Chris@35: } Chris@36: if (!getEnvUtf8("ProgramFiles(x86)", pfiles32)) { Chris@35: pfiles32 = "C:\\Program Files (x86)"; Chris@35: } Chris@35: Chris@35: string::size_type f; Chris@35: while ((f = path.find("%ProgramFiles%")) != string::npos && Chris@35: f < path.length()) { Chris@35: if (m_format == FormatNonNative32Bit) { Chris@35: path.replace(f, 14, pfiles32); Chris@35: } else { Chris@35: path.replace(f, 14, pfiles); Chris@35: } Chris@35: } Chris@35: #endif Chris@35: Chris@35: return path; Chris@35: } Chris@35: Chris@4: vector Chris@35: KnownPlugins::expandPathString(string path) Chris@4: { Chris@4: vector pathList; Chris@4: Chris@4: string::size_type index = 0, newindex = 0; Chris@4: Chris@4: while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) { Chris@19: pathList.push_back(path.substr(index, newindex - index).c_str()); Chris@19: index = newindex + 1; Chris@4: } Chris@4: Chris@4: pathList.push_back(path.substr(index)); Chris@4: Chris@4: return pathList; Chris@4: } Chris@4: Chris@35: vector Chris@35: KnownPlugins::expandConventionalPath(PluginType type, string var) Chris@4: { Chris@35: string path; Chris@4: Chris@36: if (!getEnvUtf8(var, path)) { Chris@35: path = getDefaultPathString(type); Chris@4: } Chris@4: Chris@35: return expandPathString(path); Chris@4: }