[PATCH v2 1/2] winepulse: Try to obtain shorter device names if it exceeds 62 chars.

Gabriel Ivăncescu gabrielopcode at gmail.com
Thu May 26 09:07:56 CDT 2022


If the device desc is longer than the limit, we try to obtain product
name or alsa name (whichever is shorter) but only if both fit within the
limit, as otherwise there is no point to do it anyway (and avoids another
allocation, simplifying the code). Then the profile desc is appended if it
doesn't cause us to exceed the limit.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53010
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

I've done some testing with this by hacking the checks. Sometimes, the desc
is even shorter than the device name (e.g. for "Built-In Analog Stereo"
case), so it's always the first attempt.

Note that we have to check the length *after* conversion to WCHAR since it
can change. We can't rely on the source string's length (also we can't assume
UTF8 if host CP is something else, which ntdll_umbstowcs takes care of).

 dlls/winepulse.drv/pulse.c | 94 +++++++++++++++++++++++++++++++++-----
 1 file changed, 82 insertions(+), 12 deletions(-)

diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c
index 1254509..47860fa 100644
--- a/dlls/winepulse.drv/pulse.c
+++ b/dlls/winepulse.drv/pulse.c
@@ -426,6 +426,83 @@ static UINT pulse_channel_map_to_channel_mask(const pa_channel_map *map)
     return mask;
 }
 
+static WCHAR *get_device_name(const char *desc, pa_proplist *proplist)
+{
+    /*
+       Some broken apps (e.g. Split/Second with fmodex) can't handle names that
+       are too long and crash even on native. If the device desc is too long,
+       we'll attempt to incrementally build it to try to stay under the limit.
+       ( + 1 is to check against full buffer after ntdll_umbstowcs )
+    */
+    WCHAR buf[62 + 1];
+
+    /* For monitors of sinks; this does not seem to be localized in PA either */
+    static const WCHAR monitor_of[] = {'M','o','n','i','t','o','r',' ','o','f',' '};
+
+    size_t len = strlen(desc);
+    WCHAR *name, *tmp;
+
+    if (!(name = malloc((len + 1) * sizeof(WCHAR))))
+        return NULL;
+    if (!(len = ntdll_umbstowcs(desc, len, name, len))) {
+        free(name);
+        return NULL;
+    }
+
+    if (len >= ARRAY_SIZE(buf) && proplist) {
+        const char *prop = pa_proplist_gets(proplist, PA_PROP_DEVICE_CLASS);
+        const char *product_name, *alsa_name;
+        unsigned product_len, alsa_len;
+        unsigned rem = ARRAY_SIZE(buf);
+        BOOL monitor = FALSE;
+
+        if (prop && !strcmp(prop, "monitor")) {
+            rem -= ARRAY_SIZE(monitor_of);
+            monitor = TRUE;
+        }
+
+        product_name = pa_proplist_gets(proplist, PA_PROP_DEVICE_PRODUCT_NAME);
+        if (!product_name || !product_name[0] ||
+            !(product_len = ntdll_umbstowcs(product_name, strlen(product_name), buf, rem)) || product_len == rem)
+            product_name = NULL;
+
+        alsa_name = pa_proplist_gets(proplist, "alsa.card_name");
+        if (!alsa_name || !alsa_name[0] ||
+            !(alsa_len = ntdll_umbstowcs(alsa_name, strlen(alsa_name), buf, rem)) || alsa_len == rem)
+            alsa_name = NULL;
+
+        prop = !product_name || (alsa_name && alsa_len < product_len) ? alsa_name : product_name;
+        if (prop) {
+            /* We know we have a name that fits within the limit now */
+            WCHAR *p = name;
+
+            if (monitor) {
+                memcpy(p, monitor_of, sizeof(monitor_of));
+                p += ARRAY_SIZE(monitor_of);
+            }
+            len = ntdll_umbstowcs(prop, strlen(prop), p, rem);
+            rem -= len;
+            p += len;
+
+            if (rem > 2) {
+                rem--;  /* space */
+
+                prop = pa_proplist_gets(proplist, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
+                if (prop && prop[0] && (len = ntdll_umbstowcs(prop, strlen(prop), p + 1, rem)) && len != rem) {
+                    *p++ = ' ';
+                    p += len;
+                }
+            }
+            len = p - name;
+        }
+    }
+    name[len] = '\0';
+
+    if ((tmp = realloc(name, (len + 1) * sizeof(WCHAR))))
+        name = tmp;
+    return name;
+}
+
 static void fill_device_info(PhysDevice *dev, pa_proplist *p)
 {
     const char *buffer;
@@ -452,27 +529,18 @@ static void fill_device_info(PhysDevice *dev, pa_proplist *p)
 }
 
 static void pulse_add_device(struct list *list, pa_proplist *proplist, int index, EndpointFormFactor form,
-                             UINT channel_mask, const char *pulse_name, const char *name)
+                             UINT channel_mask, const char *pulse_name, const char *desc)
 {
-    size_t len = strlen(pulse_name), name_len = strlen(name);
+    size_t len = strlen(pulse_name);
     PhysDevice *dev = malloc(FIELD_OFFSET(PhysDevice, pulse_name[len + 1]));
-    WCHAR *wname;
 
     if (!dev)
         return;
 
-    if (!(wname = malloc((name_len + 1) * sizeof(WCHAR)))) {
+    if (!(dev->name = get_device_name(desc, proplist))) {
         free(dev);
         return;
     }
-
-    if (!(name_len = ntdll_umbstowcs(name, name_len, wname, name_len)) ||
-        !(dev->name = realloc(wname, (name_len + 1) * sizeof(WCHAR)))) {
-        free(wname);
-        free(dev);
-        return;
-    }
-    dev->name[name_len] = 0;
     dev->form = form;
     dev->index = index;
     dev->channel_mask = channel_mask;
@@ -480,6 +548,8 @@ static void pulse_add_device(struct list *list, pa_proplist *proplist, int index
     memcpy(dev->pulse_name, pulse_name, len + 1);
 
     list_add_tail(list, &dev->entry);
+
+    TRACE("%s\n", debugstr_w(dev->name));
 }
 
 static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
-- 
2.34.1




More information about the wine-devel mailing list