]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/utf8.c
udev: set errno = ENOSYS for removed interfaces
[thirdparty/systemd.git] / src / utf8.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 /* This file is based on the GLIB utf8 validation functions. The
23 * original license text follows. */
24
25 /* gutf8.c - Operations on UTF-8 strings.
26 *
27 * Copyright (C) 1999 Tom Tromey
28 * Copyright (C) 2000 Red Hat, Inc.
29 *
30 * This library is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU Lesser General Public
32 * License as published by the Free Software Foundation; either
33 * version 2 of the License, or (at your option) any later version.
34 *
35 * This library is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38 * Lesser General Public License for more details.
39 *
40 * You should have received a copy of the GNU Lesser General Public
41 * License along with this library; if not, write to the
42 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
43 * Boston, MA 02111-1307, USA.
44 */
45
46 #include <errno.h>
47 #include <stdlib.h>
48 #include <inttypes.h>
49 #include <string.h>
50 #include <stdbool.h>
51
52 #include "utf8.h"
53
54 #define FILTER_CHAR '_'
55
56 static inline bool is_unicode_valid(uint32_t ch) {
57
58 if (ch >= 0x110000) /* End of unicode space */
59 return false;
60 if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */
61 return false;
62 if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */
63 return false;
64 if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */
65 return false;
66
67 return true;
68 }
69
70 static inline bool is_continuation_char(uint8_t ch) {
71 if ((ch & 0xc0) != 0x80) /* 10xxxxxx */
72 return false;
73 return true;
74 }
75
76 static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) {
77 *u_ch <<= 6;
78 *u_ch |= ch & 0x3f;
79 }
80
81 static char* utf8_validate(const char *str, char *output) {
82 uint32_t val = 0;
83 uint32_t min = 0;
84 const uint8_t *p, *last;
85 int size;
86 uint8_t *o;
87
88 assert(str);
89
90 o = (uint8_t*) output;
91 for (p = (const uint8_t*) str; *p; p++) {
92 if (*p < 128) {
93 if (o)
94 *o = *p;
95 } else {
96 last = p;
97
98 if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */
99 size = 2;
100 min = 128;
101 val = (uint32_t) (*p & 0x1e);
102 goto ONE_REMAINING;
103 } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/
104 size = 3;
105 min = (1 << 11);
106 val = (uint32_t) (*p & 0x0f);
107 goto TWO_REMAINING;
108 } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */
109 size = 4;
110 min = (1 << 16);
111 val = (uint32_t) (*p & 0x07);
112 } else
113 goto error;
114
115 p++;
116 if (!is_continuation_char(*p))
117 goto error;
118 merge_continuation_char(&val, *p);
119
120 TWO_REMAINING:
121 p++;
122 if (!is_continuation_char(*p))
123 goto error;
124 merge_continuation_char(&val, *p);
125
126 ONE_REMAINING:
127 p++;
128 if (!is_continuation_char(*p))
129 goto error;
130 merge_continuation_char(&val, *p);
131
132 if (val < min)
133 goto error;
134
135 if (!is_unicode_valid(val))
136 goto error;
137
138 if (o) {
139 memcpy(o, last, (size_t) size);
140 o += size;
141 }
142
143 continue;
144
145 error:
146 if (o) {
147 *o = FILTER_CHAR;
148 p = last; /* We retry at the next character */
149 } else
150 goto failure;
151 }
152
153 if (o)
154 o++;
155 }
156
157 if (o) {
158 *o = '\0';
159 return output;
160 }
161
162 return (char*) str;
163
164 failure:
165 return NULL;
166 }
167
168 char* utf8_is_valid (const char *str) {
169 return utf8_validate(str, NULL);
170 }
171
172 char* utf8_filter (const char *str) {
173 char *new_str;
174
175 assert(str);
176
177 new_str = malloc(strlen(str) + 1);
178 if (!new_str)
179 return NULL;
180
181 return utf8_validate(str, new_str);
182 }
183
184 char *ascii_is_valid(const char *str) {
185 const char *p;
186
187 assert(str);
188
189 for (p = str; *p; p++)
190 if ((unsigned char) *p >= 128)
191 return NULL;
192
193 return (char*) str;
194 }
195
196 char *ascii_filter(const char *str) {
197 char *r, *s, *d;
198 size_t l;
199
200 assert(str);
201
202 l = strlen(str);
203 r = malloc(l + 1);
204 if (!r)
205 return NULL;
206
207 for (s = r, d = r; *s; s++)
208 if ((unsigned char) *s < 128)
209 *(d++) = *s;
210
211 *d = 0;
212
213 return r;
214 }