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