ALSA: pcm: Fix missing check of the new non-cached buffer type
[linux-2.6-block.git] / fs / unicode / utf8-core.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/string.h>
5 #include <linux/slab.h>
6 #include <linux/parser.h>
7 #include <linux/errno.h>
8 #include <linux/unicode.h>
9
10 #include "utf8n.h"
11
12 int utf8_validate(const struct unicode_map *um, const struct qstr *str)
13 {
14         const struct utf8data *data = utf8nfdi(um->version);
15
16         if (utf8nlen(data, str->name, str->len) < 0)
17                 return -1;
18         return 0;
19 }
20 EXPORT_SYMBOL(utf8_validate);
21
22 int utf8_strncmp(const struct unicode_map *um,
23                  const struct qstr *s1, const struct qstr *s2)
24 {
25         const struct utf8data *data = utf8nfdi(um->version);
26         struct utf8cursor cur1, cur2;
27         int c1, c2;
28
29         if (utf8ncursor(&cur1, data, s1->name, s1->len) < 0)
30                 return -EINVAL;
31
32         if (utf8ncursor(&cur2, data, s2->name, s2->len) < 0)
33                 return -EINVAL;
34
35         do {
36                 c1 = utf8byte(&cur1);
37                 c2 = utf8byte(&cur2);
38
39                 if (c1 < 0 || c2 < 0)
40                         return -EINVAL;
41                 if (c1 != c2)
42                         return 1;
43         } while (c1);
44
45         return 0;
46 }
47 EXPORT_SYMBOL(utf8_strncmp);
48
49 int utf8_strncasecmp(const struct unicode_map *um,
50                      const struct qstr *s1, const struct qstr *s2)
51 {
52         const struct utf8data *data = utf8nfdicf(um->version);
53         struct utf8cursor cur1, cur2;
54         int c1, c2;
55
56         if (utf8ncursor(&cur1, data, s1->name, s1->len) < 0)
57                 return -EINVAL;
58
59         if (utf8ncursor(&cur2, data, s2->name, s2->len) < 0)
60                 return -EINVAL;
61
62         do {
63                 c1 = utf8byte(&cur1);
64                 c2 = utf8byte(&cur2);
65
66                 if (c1 < 0 || c2 < 0)
67                         return -EINVAL;
68                 if (c1 != c2)
69                         return 1;
70         } while (c1);
71
72         return 0;
73 }
74 EXPORT_SYMBOL(utf8_strncasecmp);
75
76 /* String cf is expected to be a valid UTF-8 casefolded
77  * string.
78  */
79 int utf8_strncasecmp_folded(const struct unicode_map *um,
80                             const struct qstr *cf,
81                             const struct qstr *s1)
82 {
83         const struct utf8data *data = utf8nfdicf(um->version);
84         struct utf8cursor cur1;
85         int c1, c2;
86         int i = 0;
87
88         if (utf8ncursor(&cur1, data, s1->name, s1->len) < 0)
89                 return -EINVAL;
90
91         do {
92                 c1 = utf8byte(&cur1);
93                 c2 = cf->name[i++];
94                 if (c1 < 0)
95                         return -EINVAL;
96                 if (c1 != c2)
97                         return 1;
98         } while (c1);
99
100         return 0;
101 }
102 EXPORT_SYMBOL(utf8_strncasecmp_folded);
103
104 int utf8_casefold(const struct unicode_map *um, const struct qstr *str,
105                   unsigned char *dest, size_t dlen)
106 {
107         const struct utf8data *data = utf8nfdicf(um->version);
108         struct utf8cursor cur;
109         size_t nlen = 0;
110
111         if (utf8ncursor(&cur, data, str->name, str->len) < 0)
112                 return -EINVAL;
113
114         for (nlen = 0; nlen < dlen; nlen++) {
115                 int c = utf8byte(&cur);
116
117                 dest[nlen] = c;
118                 if (!c)
119                         return nlen;
120                 if (c == -1)
121                         break;
122         }
123         return -EINVAL;
124 }
125
126 EXPORT_SYMBOL(utf8_casefold);
127
128 int utf8_normalize(const struct unicode_map *um, const struct qstr *str,
129                    unsigned char *dest, size_t dlen)
130 {
131         const struct utf8data *data = utf8nfdi(um->version);
132         struct utf8cursor cur;
133         ssize_t nlen = 0;
134
135         if (utf8ncursor(&cur, data, str->name, str->len) < 0)
136                 return -EINVAL;
137
138         for (nlen = 0; nlen < dlen; nlen++) {
139                 int c = utf8byte(&cur);
140
141                 dest[nlen] = c;
142                 if (!c)
143                         return nlen;
144                 if (c == -1)
145                         break;
146         }
147         return -EINVAL;
148 }
149
150 EXPORT_SYMBOL(utf8_normalize);
151
152 static int utf8_parse_version(const char *version, unsigned int *maj,
153                               unsigned int *min, unsigned int *rev)
154 {
155         substring_t args[3];
156         char version_string[12];
157         static const struct match_token token[] = {
158                 {1, "%d.%d.%d"},
159                 {0, NULL}
160         };
161
162         strncpy(version_string, version, sizeof(version_string));
163
164         if (match_token(version_string, token, args) != 1)
165                 return -EINVAL;
166
167         if (match_int(&args[0], maj) || match_int(&args[1], min) ||
168             match_int(&args[2], rev))
169                 return -EINVAL;
170
171         return 0;
172 }
173
174 struct unicode_map *utf8_load(const char *version)
175 {
176         struct unicode_map *um = NULL;
177         int unicode_version;
178
179         if (version) {
180                 unsigned int maj, min, rev;
181
182                 if (utf8_parse_version(version, &maj, &min, &rev) < 0)
183                         return ERR_PTR(-EINVAL);
184
185                 if (!utf8version_is_supported(maj, min, rev))
186                         return ERR_PTR(-EINVAL);
187
188                 unicode_version = UNICODE_AGE(maj, min, rev);
189         } else {
190                 unicode_version = utf8version_latest();
191                 printk(KERN_WARNING"UTF-8 version not specified. "
192                        "Assuming latest supported version (%d.%d.%d).",
193                        (unicode_version >> 16) & 0xff,
194                        (unicode_version >> 8) & 0xff,
195                        (unicode_version & 0xff));
196         }
197
198         um = kzalloc(sizeof(struct unicode_map), GFP_KERNEL);
199         if (!um)
200                 return ERR_PTR(-ENOMEM);
201
202         um->charset = "UTF-8";
203         um->version = unicode_version;
204
205         return um;
206 }
207 EXPORT_SYMBOL(utf8_load);
208
209 void utf8_unload(struct unicode_map *um)
210 {
211         kfree(um);
212 }
213 EXPORT_SYMBOL(utf8_unload);
214
215 MODULE_LICENSE("GPL v2");