diff --git a/extras/Build/CMake/JUCEUtils.cmake b/extras/Build/CMake/JUCEUtils.cmake index d86ce8a997..954a435db5 100644 --- a/extras/Build/CMake/JUCEUtils.cmake +++ b/extras/Build/CMake/JUCEUtils.cmake @@ -843,7 +843,7 @@ function(_juce_add_lv2_manifest_helper_target) set(source "${module_path}/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp") add_executable(juce_lv2_helper "${source}") add_executable(juce::juce_lv2_helper ALIAS juce_lv2_helper) - target_compile_features(juce_lv2_helper PRIVATE cxx_std_14) + target_compile_features(juce_lv2_helper PRIVATE cxx_std_17) set_target_properties(juce_lv2_helper PROPERTIES BUILD_WITH_INSTALL_RPATH ON) target_link_libraries(juce_lv2_helper PRIVATE ${CMAKE_DL_LIBS}) endfunction() diff --git a/modules/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp b/modules/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp index 1e4a4bc15d..c4ca28b39c 100644 --- a/modules/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp +++ b/modules/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp @@ -25,11 +25,19 @@ #include #include +#include +#include #ifdef _WIN32 + #undef UNICODE + #undef _UNICODE + + #define UNICODE 1 + #define _UNICODE 1 + #include #include - HMODULE dlopen (const char* filename, int) { return LoadLibrary (filename); } + HMODULE dlopen (const TCHAR* filename, int) { return LoadLibrary (filename); } FARPROC dlsym (HMODULE handle, const char* name) { return GetProcAddress (handle, name); } void printError() { @@ -44,12 +52,61 @@ numElements - 1, nullptr); - _tprintf ("%s", messageBuffer); + _tprintf (_T ("%s"), messageBuffer); } + enum { RTLD_LAZY = 0 }; + + class ArgList + { + public: + ArgList (int, const char**) {} + ArgList (const ArgList&) = delete; + ArgList (ArgList&&) = delete; + ArgList& operator= (const ArgList&) = delete; + ArgList& operator= (ArgList&&) = delete; + ~ArgList() { LocalFree (argv); } + + LPWSTR get (int i) const { return argv[i]; } + + int size() const { return argc; } + + private: + int argc = 0; + LPWSTR* argv = CommandLineToArgvW (GetCommandLineW(), &argc); + }; + + std::vector toUTF8 (const TCHAR* str) + { + const auto numBytes = WideCharToMultiByte (CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr); + std::vector result (numBytes); + WideCharToMultiByte (CP_UTF8, 0, str, -1, result.data(), static_cast (result.size()), nullptr, nullptr); + return result; + } + #else #include void printError() { printf ("%s\n", dlerror()); } + class ArgList + { + public: + ArgList (int argcIn, const char** argvIn) : argc (argcIn), argv (argvIn) {} + ArgList (const ArgList&) = delete; + ArgList (ArgList&&) = delete; + ArgList& operator= (const ArgList&) = delete; + ArgList& operator= (ArgList&&) = delete; + ~ArgList() = default; + + const char* get (int i) const { return argv[i]; } + + int size() const { return argc; } + + private: + int argc = 0; + const char** argv = nullptr; + }; + + std::vector toUTF8 (const char* str) { return std::vector (str, str + std::strlen (str) + 1); } #endif // Replicating part of the LV2 header here so that we don't have to set up any @@ -74,10 +131,12 @@ extern "C" int main (int argc, const char** argv) { - if (argc != 2) + const ArgList argList { argc, argv }; + + if (argList.size() != 2) return 1; - const auto* libraryPath = argv[1]; + const auto* libraryPath = argList.get (1); struct RecallFeature { @@ -87,11 +146,22 @@ int main (int argc, const char** argv) if (auto* handle = dlopen (libraryPath, RTLD_LAZY)) { if (auto* getDescriptor = reinterpret_cast (dlsym (handle, "lv2_descriptor"))) + { if (auto* descriptor = getDescriptor (0)) + { if (auto* extensionData = descriptor->extension_data) + { if (auto* recallFeature = reinterpret_cast (extensionData ("https://lv2-extensions.juce.com/turtle_recall"))) + { if (auto* doRecall = recallFeature->doRecall) - return doRecall (libraryPath); + { + const auto converted = toUTF8 (libraryPath); + return doRecall (converted.data()); + } + } + } + } + } } else { diff --git a/modules/juce_audio_plugin_client/LV2/juce_LV2_Client.cpp b/modules/juce_audio_plugin_client/LV2/juce_LV2_Client.cpp index 778c5c6a6d..2c1619b628 100644 --- a/modules/juce_audio_plugin_client/LV2/juce_LV2_Client.cpp +++ b/modules/juce_audio_plugin_client/LV2/juce_LV2_Client.cpp @@ -840,15 +840,28 @@ private: return JucePlugin_LV2URI + String (uriSeparator) + "preset" + String (index + 1); } - static std::ofstream openStream (const File& libraryPath, StringRef name) + static FileOutputStream openStream (const File& libraryPath, StringRef name) { - return std::ofstream { libraryPath.getSiblingFile (name + ".ttl").getFullPathName().toRawUTF8() }; + return FileOutputStream { libraryPath.getSiblingFile (name + ".ttl") }; + } + + static Result prepareStream (FileOutputStream& stream) + { + if (const auto result = stream.getStatus(); ! result) + return result; + + stream.setPosition (0); + stream.truncate(); + return Result::ok(); } static Result writeManifestTtl (AudioProcessor& proc, const File& libraryPath) { auto os = openStream (libraryPath, "manifest"); + if (const auto result = prepareStream (os); ! result) + return result; + os << "@prefix lv2: .\n" "@prefix rdfs: .\n" "@prefix pset: .\n" @@ -980,6 +993,9 @@ private: { auto os = openStream (libraryPath, "dsp"); + if (const auto result = prepareStream (os); ! result) + return result; + os << "@prefix atom: .\n" "@prefix bufs: .\n" "@prefix doap: .\n" @@ -1317,6 +1333,9 @@ private: auto os = openStream (libraryPath, "ui"); + if (const auto result = prepareStream (os); ! result) + return result; + const auto editorInstance = rawToUniquePtr (proc.createEditor()); const auto resizeFeatureString = editorInstance->isResizable() ? "ui:resize" : "ui:noUserResize";