Skip to content

VST3: convert strings between UTF-8 and UTF-16 properly - #551

Open
kokosiarz wants to merge 1 commit into
DISTRHO:developfrom
kokosiarz:vst3-utf16
Open

kokosiarz wants to merge 1 commit into
DISTRHO:developfrom
kokosiarz:vst3-utf16

Conversation

@kokosiarz

Copy link
Copy Markdown

strncpy_utf16, strncpy_utf8 and strcmp_utf16 in DistrhoPluginVST.hpp skip every character outside ASCII (// skip non-ascii chars, unsupported). strncpy_utf16 does it with continue, so the skipped units are never written and the host sees whatever was in its buffer at those positions, at an unchanged string length. Parameter names and units such as "µs" or "°" reach a VST3 host as garbage.

The state-set messages between the controller and the view go through the same helpers, so a state value holding non-ASCII text is corrupted on its way across, for example a file path with an accented letter, which then fails to open. VST2 and CLAP pass these strings as UTF-8 and are not affected, so the same plugin works in those formats and not in VST3.

This makes the helpers decode and encode UTF-8 and UTF-16 properly, surrogate pairs included:

  • malformed input (invalid or overlong UTF-8, unpaired surrogates) becomes U+FFFD
  • output is always null-terminated, and truncation never splits a character
  • the two state-set receivers (notify_state in the plugin, state-set in the UI) convert into a buffer of their own instead of narrowing each 16-bit unit to a byte in place

A UTF-16 copy never needs more units than the UTF-8 had bytes, so ScopedUTF16String's strlen() + 1 allocation and the receivers' buffers, which are sized from the sender's strlen(), still fit.

Tested with a standalone program against the helpers, with expected code units spelled out by hand: BMP and astral round trips, strcmp_utf16, truncation at a surrogate pair and at a multi-byte sequence, cut-short, overlong and surrogate-encoded UTF-8, lone high and low surrogates, plain ASCII. All 16 checks pass; stock develop fails 10 of them. Built and used in a set of ~26 DPF plugins on Windows (VST3 and CLAP).

strncpy_utf16, strncpy_utf8 and strcmp_utf16 skipped every character
outside ASCII ("skip non-ascii chars, unsupported"). strncpy_utf16 did
it with `continue`, so the skipped units were never written and the
host saw whatever was in its buffer, at an unchanged length. Parameter
names and units such as "µs" or "°" reached the host as garbage.

The state-set messages between controller and view went through the
same helpers, so any state value holding non-ASCII text was cut short
or corrupted on its way across, for example a file path with an
accented letter in it. VST2 and CLAP pass these strings as UTF-8 and
are not affected.

The helpers now decode and encode UTF-8 and UTF-16 including surrogate
pairs. Malformed input becomes U+FFFD, the output is always null
terminated, and truncation never splits a character. The two state-set
receivers convert into a buffer of their own instead of narrowing each
unit to a byte in place.

A UTF-16 copy never needs more units than the UTF-8 had bytes, so
ScopedUTF16String's strlen() + 1 allocation and the receivers' buffers,
sized by the sender's strlen(), still fit.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant