diff options
Diffstat (limited to 'src/modules/udev-util.c')
-rw-r--r-- | src/modules/udev-util.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/src/modules/udev-util.c b/src/modules/udev-util.c index cc824465..eee5409a 100644 --- a/src/modules/udev-util.c +++ b/src/modules/udev-util.c @@ -58,6 +58,112 @@ static int read_id(struct udev_device *d, const char *n) { return u; } +static int dehex(char x) { + if (x >= '0' && x <= '9') + return x - '0'; + + if (x >= 'A' && x <= 'F') + return x - 'A'; + + if (x >= 'a' && x <= 'f') + return x - 'a'; + + return -1; +} + +static void proplist_sets_unescape(pa_proplist *p, const char *prop, const char *s) { + const char *f; + char *t, *r; + int c; + + enum { + TEXT, + BACKSLASH, + EX, + FIRST + } state = TEXT; + + /* The resulting string is definitely shorter than the source string */ + r = pa_xnew(char, strlen(s)+1); + + for (f = s, t = r; *f; f++) { + + switch (state) { + + case TEXT: + if (*f == '\\') + state = BACKSLASH; + else + *(t++) = *f; + break; + + case BACKSLASH: + if (*f == 'x') + state = EX; + else { + *(t++) = '\\'; + *(t++) = *f; + state = TEXT; + } + break; + + case EX: + c = dehex(*f); + + if (c < 0) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = *f; + state = TEXT; + } else + state = FIRST; + + break; + + case FIRST: { + int d = dehex(*f); + + if (d < 0) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = *(f-1); + *(t++) = *f; + } else + *(t++) = (char) (c << 4) | d; + + state = TEXT; + break; + } + } + } + + switch (state) { + + case TEXT: + break; + + case BACKSLASH: + *(t++) = '\\'; + break; + + case EX: + *(t++) = '\\'; + *(t++) = 'x'; + break; + + case FIRST: + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = *(f-1); + break; + } + + *t = 0; + + pa_proplist_sets(p, prop, r); + pa_xfree(r); +} + int pa_udev_get_info(int card_idx, pa_proplist *p) { int r = -1; struct udev *udev; @@ -107,6 +213,8 @@ int pa_udev_get_info(int card_idx, pa_proplist *p) { if (!pa_proplist_contains(p, PA_PROP_DEVICE_VENDOR_NAME)) { if ((v = udev_device_get_property_value(card, "ID_VENDOR_FROM_DATABASE")) && *v) pa_proplist_sets(p, PA_PROP_DEVICE_VENDOR_NAME, v); + else if ((v = udev_device_get_property_value(card, "ID_VENDOR_ENC")) && *v) + proplist_sets_unescape(p, PA_PROP_DEVICE_VENDOR_NAME, v); else if ((v = udev_device_get_property_value(card, "ID_VENDOR")) && *v) pa_proplist_sets(p, PA_PROP_DEVICE_VENDOR_NAME, v); } @@ -118,6 +226,8 @@ int pa_udev_get_info(int card_idx, pa_proplist *p) { if (!pa_proplist_contains(p, PA_PROP_DEVICE_PRODUCT_NAME)) { if ((v = udev_device_get_property_value(card, "ID_MODEL_FROM_DATABASE")) && *v) pa_proplist_sets(p, PA_PROP_DEVICE_PRODUCT_NAME, v); + else if ((v = udev_device_get_property_value(card, "ID_MODEL_ENC")) && *v) + proplist_sets_unescape(p, PA_PROP_DEVICE_PRODUCT_NAME, v); else if ((v = udev_device_get_property_value(card, "ID_MODEL")) && *v) pa_proplist_sets(p, PA_PROP_DEVICE_PRODUCT_NAME, v); } |