1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
6 #include <linux/string.h>
10 static u16 bad_uni_chars[] = {
11 /* " * / : < > ? \ | */
12 0x0022, 0x002A, 0x002F, 0x003A,
13 0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
17 static int convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch,
29 len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni);
31 /* conversion failed */
32 pr_info("%s: fail to use nls\n", __func__);
36 if (!strcmp(nls->charset, "utf8"))
45 static int convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni,
57 len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE);
59 /* conversion failed */
60 pr_info("%s: fail to use nls\n", __func__);
70 u16 nls_upper(struct super_block *sb, u16 a)
72 struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
74 if (EXFAT_SB(sb)->options.casesensitive)
76 if (p_fs->vol_utbl && p_fs->vol_utbl[get_col_index(a)])
77 return p_fs->vol_utbl[get_col_index(a)][get_row_index(a)];
82 static u16 *nls_wstrchr(u16 *str, u16 wchar)
85 if (*(str++) == wchar)
92 int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b)
96 for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
97 if (nls_upper(sb, *a) != nls_upper(sb, *b))
105 void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring,
106 struct uni_name_t *p_uniname)
109 u8 buf[MAX_CHARSET_SIZE];
110 u16 *uniname = p_uniname->name;
111 struct nls_table *nls = EXFAT_SB(sb)->nls_io;
114 len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH,
115 UTF16_HOST_ENDIAN, p_cstring,
122 while (i < (MAX_NAME_LENGTH - 1)) {
123 if (*uniname == (u16)'\0')
126 len = convert_uni_to_ch(nls, buf, *uniname, NULL);
129 for (j = 0; j < len; j++)
130 *p_cstring++ = (char)*(buf + j);
131 } else { /* len == 1 */
132 *p_cstring++ = (char)*buf;
142 void nls_cstring_to_uniname(struct super_block *sb,
143 struct uni_name_t *p_uniname, u8 *p_cstring,
149 u8 upname[MAX_NAME_LENGTH * 2];
150 u16 *uniname = p_uniname->name;
151 struct nls_table *nls = EXFAT_SB(sb)->nls_io;
153 /* strip all trailing spaces */
154 end_of_name = p_cstring + strlen(p_cstring);
156 while (*(--end_of_name) == ' ') {
157 if (end_of_name < p_cstring)
160 *(++end_of_name) = '\0';
162 if (strcmp(p_cstring, ".") && strcmp(p_cstring, "..")) {
163 /* strip all trailing periods */
164 while (*(--end_of_name) == '.') {
165 if (end_of_name < p_cstring)
168 *(++end_of_name) = '\0';
171 if (*p_cstring == '\0')
175 i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH,
176 UTF16_HOST_ENDIAN, uniname,
178 for (j = 0; j < i; j++)
179 SET16_A(upname + j * 2, nls_upper(sb, uniname[j]));
184 while (j < (MAX_NAME_LENGTH - 1)) {
185 if (*(p_cstring + i) == '\0')
188 i += convert_ch_to_uni(nls, uniname,
189 (u8 *)(p_cstring + i), &lossy);
191 if ((*uniname < 0x0020) ||
192 nls_wstrchr(bad_uni_chars, *uniname))
195 SET16_A(upname + j * 2, nls_upper(sb, *uniname));
201 if (*(p_cstring + i) != '\0')
203 *uniname = (u16)'\0';
206 p_uniname->name_len = j;
207 p_uniname->name_hash = calc_checksum_2byte(upname, j << 1, 0,