1*b990a06fSArmin Wolf // SPDX-License-Identifier: GPL-2.0-or-later 2*b990a06fSArmin Wolf /* 3*b990a06fSArmin Wolf * WMI string utility functions. 4*b990a06fSArmin Wolf * 5*b990a06fSArmin Wolf * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de> 6*b990a06fSArmin Wolf */ 7*b990a06fSArmin Wolf 8*b990a06fSArmin Wolf #include <linux/build_bug.h> 9*b990a06fSArmin Wolf #include <linux/compiler_types.h> 10*b990a06fSArmin Wolf #include <linux/err.h> 11*b990a06fSArmin Wolf #include <linux/export.h> 12*b990a06fSArmin Wolf #include <linux/nls.h> 13*b990a06fSArmin Wolf #include <linux/limits.h> 14*b990a06fSArmin Wolf #include <linux/types.h> 15*b990a06fSArmin Wolf #include <linux/wmi.h> 16*b990a06fSArmin Wolf 17*b990a06fSArmin Wolf #include <asm/byteorder.h> 18*b990a06fSArmin Wolf 19*b990a06fSArmin Wolf static_assert(sizeof(__le16) == sizeof(wchar_t)); 20*b990a06fSArmin Wolf 21*b990a06fSArmin Wolf /** 22*b990a06fSArmin Wolf * wmi_string_to_utf8s - Convert a WMI string into a UTF8 string. 23*b990a06fSArmin Wolf * @str: WMI string representation 24*b990a06fSArmin Wolf * @dst: Buffer to fill with UTF8 characters 25*b990a06fSArmin Wolf * @length: Length of the destination buffer 26*b990a06fSArmin Wolf * 27*b990a06fSArmin Wolf * Convert as WMI string into a standard UTF8 string. The conversion will stop 28*b990a06fSArmin Wolf * once a NUL character is detected or when the buffer is full. Any invalid UTF16 29*b990a06fSArmin Wolf * characters will be ignored. The resulting UTF8 string will always be NUL-terminated 30*b990a06fSArmin Wolf * when this function returns successfully. 31*b990a06fSArmin Wolf * 32*b990a06fSArmin Wolf * Return: Length of the resulting UTF8 string or negative errno code on failure. 33*b990a06fSArmin Wolf */ 34*b990a06fSArmin Wolf ssize_t wmi_string_to_utf8s(const struct wmi_string *str, u8 *dst, size_t length) 35*b990a06fSArmin Wolf { 36*b990a06fSArmin Wolf /* Contains the maximum number of UTF16 code points to read */ 37*b990a06fSArmin Wolf int inlen = le16_to_cpu(str->length) / 2; 38*b990a06fSArmin Wolf int ret; 39*b990a06fSArmin Wolf 40*b990a06fSArmin Wolf if (length < 1) 41*b990a06fSArmin Wolf return -EINVAL; 42*b990a06fSArmin Wolf 43*b990a06fSArmin Wolf /* We must leave room for the NUL character at the end of the destination buffer */ 44*b990a06fSArmin Wolf ret = utf16s_to_utf8s((__force const wchar_t *)str->chars, inlen, UTF16_LITTLE_ENDIAN, dst, 45*b990a06fSArmin Wolf length - 1); 46*b990a06fSArmin Wolf if (ret < 0) 47*b990a06fSArmin Wolf return ret; 48*b990a06fSArmin Wolf 49*b990a06fSArmin Wolf dst[ret] = '\0'; 50*b990a06fSArmin Wolf 51*b990a06fSArmin Wolf return ret; 52*b990a06fSArmin Wolf } 53*b990a06fSArmin Wolf EXPORT_SYMBOL_GPL(wmi_string_to_utf8s); 54*b990a06fSArmin Wolf 55*b990a06fSArmin Wolf /** 56*b990a06fSArmin Wolf * wmi_string_from_utf8s - Convert a UTF8 string into a WMI string. 57*b990a06fSArmin Wolf * @str: WMI string representation 58*b990a06fSArmin Wolf * @max_chars: Maximum number of UTF16 code points to store inside the WMI string 59*b990a06fSArmin Wolf * @src: UTF8 string to convert 60*b990a06fSArmin Wolf * @src_length: Length of the source string without any trailing NUL-characters 61*b990a06fSArmin Wolf * 62*b990a06fSArmin Wolf * Convert a UTF8 string into a WMI string. The conversion will stop when the WMI string is 63*b990a06fSArmin Wolf * full. The resulting WMI string will always be NUL-terminated and have its length field set 64*b990a06fSArmin Wolf * to and appropriate value when this function returns successfully. 65*b990a06fSArmin Wolf * 66*b990a06fSArmin Wolf * Return: Number of UTF16 code points inside the WMI string or negative errno code on failure. 67*b990a06fSArmin Wolf */ 68*b990a06fSArmin Wolf ssize_t wmi_string_from_utf8s(struct wmi_string *str, size_t max_chars, const u8 *src, 69*b990a06fSArmin Wolf size_t src_length) 70*b990a06fSArmin Wolf { 71*b990a06fSArmin Wolf size_t str_length; 72*b990a06fSArmin Wolf int ret; 73*b990a06fSArmin Wolf 74*b990a06fSArmin Wolf if (max_chars < 1) 75*b990a06fSArmin Wolf return -EINVAL; 76*b990a06fSArmin Wolf 77*b990a06fSArmin Wolf /* We must leave room for the NUL character at the end of the WMI string */ 78*b990a06fSArmin Wolf ret = utf8s_to_utf16s(src, src_length, UTF16_LITTLE_ENDIAN, (__force wchar_t *)str->chars, 79*b990a06fSArmin Wolf max_chars - 1); 80*b990a06fSArmin Wolf if (ret < 0) 81*b990a06fSArmin Wolf return ret; 82*b990a06fSArmin Wolf 83*b990a06fSArmin Wolf str_length = (ret + 1) * sizeof(u16); 84*b990a06fSArmin Wolf if (str_length > U16_MAX) 85*b990a06fSArmin Wolf return -EOVERFLOW; 86*b990a06fSArmin Wolf 87*b990a06fSArmin Wolf str->length = cpu_to_le16(str_length); 88*b990a06fSArmin Wolf str->chars[ret] = '\0'; 89*b990a06fSArmin Wolf 90*b990a06fSArmin Wolf return ret; 91*b990a06fSArmin Wolf } 92*b990a06fSArmin Wolf EXPORT_SYMBOL_GPL(wmi_string_from_utf8s); 93