The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
5.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. #include <cstdint>
  19. #include <cstdio>
  20. #include <cstring>
  21. #include <vector>
  22. #ifdef _WIN32
  23. #undef UNICODE
  24. #undef _UNICODE
  25. #define UNICODE 1
  26. #define _UNICODE 1
  27. #include <windows.h>
  28. #include <tchar.h>
  29. HMODULE dlopen (const TCHAR* filename, int) { return LoadLibrary (filename); }
  30. FARPROC dlsym (HMODULE handle, const char* name) { return GetProcAddress (handle, name); }
  31. static void printError()
  32. {
  33. constexpr DWORD numElements = 256;
  34. TCHAR messageBuffer[numElements]{};
  35. FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  36. nullptr,
  37. GetLastError(),
  38. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
  39. messageBuffer,
  40. numElements - 1,
  41. nullptr);
  42. _tprintf (_T ("%s"), messageBuffer);
  43. }
  44. enum { RTLD_LAZY = 0 };
  45. class ArgList
  46. {
  47. public:
  48. ArgList (int, const char**) {}
  49. ArgList (const ArgList&) = delete;
  50. ArgList (ArgList&&) = delete;
  51. ArgList& operator= (const ArgList&) = delete;
  52. ArgList& operator= (ArgList&&) = delete;
  53. ~ArgList() { LocalFree (argv); }
  54. LPWSTR get (int i) const { return argv[i]; }
  55. int size() const { return argc; }
  56. private:
  57. int argc = 0;
  58. LPWSTR* argv = CommandLineToArgvW (GetCommandLineW(), &argc);
  59. };
  60. static std::vector<char> toUTF8 (const TCHAR* str)
  61. {
  62. const auto numBytes = WideCharToMultiByte (CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr);
  63. std::vector<char> result (numBytes);
  64. WideCharToMultiByte (CP_UTF8, 0, str, -1, result.data(), static_cast<int> (result.size()), nullptr, nullptr);
  65. return result;
  66. }
  67. #else
  68. #include <dlfcn.h>
  69. static void printError() { printf ("%s\n", dlerror()); }
  70. class ArgList
  71. {
  72. public:
  73. ArgList (int argcIn, const char** argvIn) : argc (argcIn), argv (argvIn) {}
  74. ArgList (const ArgList&) = delete;
  75. ArgList (ArgList&&) = delete;
  76. ArgList& operator= (const ArgList&) = delete;
  77. ArgList& operator= (ArgList&&) = delete;
  78. ~ArgList() = default;
  79. const char* get (int i) const { return argv[i]; }
  80. int size() const { return argc; }
  81. private:
  82. int argc = 0;
  83. const char** argv = nullptr;
  84. };
  85. static std::vector<char> toUTF8 (const char* str) { return std::vector<char> (str, str + std::strlen (str) + 1); }
  86. #endif
  87. // Replicating part of the LV2 header here so that we don't have to set up any
  88. // custom include paths for this file.
  89. // Normally this would be a bad idea, but the LV2 API has to keep these definitions
  90. // in order to remain backwards-compatible.
  91. extern "C"
  92. {
  93. typedef struct LV2_Descriptor
  94. {
  95. const void* a;
  96. const void* b;
  97. const void* c;
  98. const void* d;
  99. const void* e;
  100. const void* f;
  101. const void* g;
  102. const void* (*extension_data)(const char* uri);
  103. } LV2_Descriptor;
  104. }
  105. int main (int argc, const char** argv)
  106. {
  107. const ArgList argList { argc, argv };
  108. if (argList.size() != 2)
  109. return 1;
  110. const auto* libraryPath = argList.get (1);
  111. struct RecallFeature
  112. {
  113. int (*doRecall) (const char*);
  114. };
  115. if (auto* handle = dlopen (libraryPath, RTLD_LAZY))
  116. {
  117. if (auto* getDescriptor = reinterpret_cast<const LV2_Descriptor* (*) (uint32_t)> (dlsym (handle, "lv2_descriptor")))
  118. {
  119. if (auto* descriptor = getDescriptor (0))
  120. {
  121. if (auto* extensionData = descriptor->extension_data)
  122. {
  123. if (auto* recallFeature = reinterpret_cast<const RecallFeature*> (extensionData ("https://lv2-extensions.juce.com/turtle_recall")))
  124. {
  125. if (auto* doRecall = recallFeature->doRecall)
  126. {
  127. const auto converted = toUTF8 (libraryPath);
  128. return doRecall (converted.data());
  129. }
  130. }
  131. }
  132. }
  133. }
  134. }
  135. else
  136. {
  137. printError();
  138. }
  139. return 1;
  140. }