diff --git a/src/wrapper/util.rs b/src/wrapper/util.rs index a336515d..0e76dcfc 100644 --- a/src/wrapper/util.rs +++ b/src/wrapper/util.rs @@ -1,8 +1,6 @@ use std::cmp; use std::marker::PhantomData; use std::os::raw::c_char; -use vst3_sys::vst::TChar; -use widestring::U16CString; #[cfg(all(debug_assertions, feature = "assert_process_allocs"))] #[global_allocator] @@ -41,29 +39,6 @@ pub fn strlcpy(dest: &mut [c_char], src: &str) { dest[copy_len] = 0; } -/// The same as [`strlcpy()`], but for VST3's fun UTF-16 strings instead. -pub fn u16strlcpy(dest: &mut [TChar], src: &str) { - if dest.is_empty() { - return; - } - - let src_utf16 = match U16CString::from_str(src) { - Ok(s) => s, - Err(err) => { - nih_debug_assert_failure!("Invalid UTF-16 string: {}", err); - return; - } - }; - let src_utf16_chars = src_utf16.as_slice(); - let src_utf16_chars_signed: &[TChar] = - unsafe { &*(src_utf16_chars as *const [u16] as *const [TChar]) }; - - // Make sure there's always room for a null terminator - let copy_len = cmp::min(dest.len() - 1, src_utf16_chars_signed.len()); - dest[..copy_len].copy_from_slice(&src_utf16_chars_signed[..copy_len]); - dest[copy_len] = 0; -} - /// A wrapper around the entire process function, including the plugin wrapper parts. This sets up /// `assert_no_alloc` if needed, while also making sure that things like FTZ are set up correctly if /// the host has not already done so. @@ -135,7 +110,6 @@ impl Drop for ScopedFtz { #[cfg(test)] mod miri { use std::ffi::CStr; - use widestring::U16CStr; use super::*; @@ -160,30 +134,4 @@ mod miri { Ok("Hello") ); } - - #[test] - fn u16strlcpy_normal() { - let mut dest = [0; 256]; - u16strlcpy(&mut dest, "Hello, world!"); - - assert_eq!( - unsafe { U16CStr::from_ptr_str(dest.as_ptr() as *const u16) } - .to_string() - .unwrap(), - "Hello, world!" - ); - } - - #[test] - fn u16strlcpy_overflow() { - let mut dest = [0; 6]; - u16strlcpy(&mut dest, "Hello, world!"); - - assert_eq!( - unsafe { U16CStr::from_ptr_str(dest.as_ptr() as *const u16) } - .to_string() - .unwrap(), - "Hello" - ); - } } diff --git a/src/wrapper/vst3/factory.rs b/src/wrapper/vst3/factory.rs index 69488891..17733808 100644 --- a/src/wrapper/vst3/factory.rs +++ b/src/wrapper/vst3/factory.rs @@ -8,9 +8,10 @@ use vst3_sys::VST3; // Alias needed for the VST3 attribute macro use vst3_sys as vst3_com; +use super::util::u16strlcpy; use super::wrapper::Wrapper; use crate::plugin::Vst3Plugin; -use crate::wrapper::util::{strlcpy, u16strlcpy}; +use crate::wrapper::util::strlcpy; /// The VST3 SDK version this is roughtly based on. const VST3_SDK_VERSION: &str = "VST 3.6.14"; diff --git a/src/wrapper/vst3/util.rs b/src/wrapper/vst3/util.rs index 94a12aea..531287ef 100644 --- a/src/wrapper/vst3/util.rs +++ b/src/wrapper/vst3/util.rs @@ -1,5 +1,9 @@ +use std::cmp; use std::ops::Deref; -use vst3_sys::{interfaces::IUnknown, ComInterface}; +use vst3_sys::interfaces::IUnknown; +use vst3_sys::vst::TChar; +use vst3_sys::ComInterface; +use widestring::U16CString; /// When `Plugin::MIDI_INPUT` is set to `MidiConfig::MidiCCs` or higher then we'll register 130*16 /// additional parameters to handle MIDI CCs, channel pressure, and pitch bend, in that order. @@ -32,6 +36,29 @@ macro_rules! check_null_ptr_msg { }; } +/// The same as [`strlcpy()`], but for VST3's fun UTF-16 strings instead. +pub fn u16strlcpy(dest: &mut [TChar], src: &str) { + if dest.is_empty() { + return; + } + + let src_utf16 = match U16CString::from_str(src) { + Ok(s) => s, + Err(err) => { + nih_debug_assert_failure!("Invalid UTF-16 string: {}", err); + return; + } + }; + let src_utf16_chars = src_utf16.as_slice(); + let src_utf16_chars_signed: &[TChar] = + unsafe { &*(src_utf16_chars as *const [u16] as *const [TChar]) }; + + // Make sure there's always room for a null terminator + let copy_len = cmp::min(dest.len() - 1, src_utf16_chars_signed.len()); + dest[..copy_len].copy_from_slice(&src_utf16_chars_signed[..copy_len]); + dest[copy_len] = 0; +} + /// Send+Sync wrapper for these interface pointers. #[repr(transparent)] pub struct VstPtr { @@ -88,3 +115,36 @@ unsafe impl Sync for VstPtr {} unsafe impl Send for ObjectPtr {} unsafe impl Sync for ObjectPtr {} + +#[cfg(test)] +mod miri { + use widestring::U16CStr; + + use super::*; + + #[test] + fn u16strlcpy_normal() { + let mut dest = [0; 256]; + u16strlcpy(&mut dest, "Hello, world!"); + + assert_eq!( + unsafe { U16CStr::from_ptr_str(dest.as_ptr() as *const u16) } + .to_string() + .unwrap(), + "Hello, world!" + ); + } + + #[test] + fn u16strlcpy_overflow() { + let mut dest = [0; 6]; + u16strlcpy(&mut dest, "Hello, world!"); + + assert_eq!( + unsafe { U16CStr::from_ptr_str(dest.as_ptr() as *const u16) } + .to_string() + .unwrap(), + "Hello" + ); + } +} diff --git a/src/wrapper/vst3/wrapper.rs b/src/wrapper/vst3/wrapper.rs index 550d19a7..69b30a11 100644 --- a/src/wrapper/vst3/wrapper.rs +++ b/src/wrapper/vst3/wrapper.rs @@ -16,7 +16,9 @@ use vst3_sys::VST3; use widestring::U16CStr; use super::inner::WrapperInner; -use super::util::{VstPtr, VST3_MIDI_CCS, VST3_MIDI_NUM_PARAMS, VST3_MIDI_PARAMS_START}; +use super::util::{ + u16strlcpy, VstPtr, VST3_MIDI_CCS, VST3_MIDI_NUM_PARAMS, VST3_MIDI_PARAMS_START, +}; use super::view::WrapperView; use crate::context::Transport; use crate::midi::{MidiConfig, NoteEvent}; @@ -24,7 +26,7 @@ use crate::param::ParamFlags; use crate::plugin::{BufferConfig, BusConfig, ProcessStatus, Vst3Plugin}; use crate::util::permit_alloc; use crate::wrapper::state; -use crate::wrapper::util::{process_wrapper, u16strlcpy}; +use crate::wrapper::util::process_wrapper; use crate::wrapper::vst3::inner::ProcessEvent; use crate::wrapper::vst3::note_expressions::NoteExpressionController; use crate::wrapper::vst3::util::{VST3_MIDI_CHANNELS, VST3_MIDI_PARAMS_END};