Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2006 Lennart Poettering
5 : : Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as
9 : : published by the Free Software Foundation; either version 2.1 of the
10 : : License, or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : Lesser General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public
18 : : License along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : /* This file is based on the GLIB utf8 validation functions. The
24 : : * original license text follows. */
25 : :
26 : : /* gutf8.c - Operations on UTF-8 strings.
27 : : *
28 : : * Copyright (C) 1999 Tom Tromey
29 : : * Copyright (C) 2000 Red Hat, Inc.
30 : : *
31 : : * This library is free software; you can redistribute it and/or
32 : : * modify it under the terms of the GNU Lesser General Public
33 : : * License as published by the Free Software Foundation; either
34 : : * version 2 of the License, or (at your option) any later version.
35 : : *
36 : : * This library is distributed in the hope that it will be useful,
37 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 : : * Lesser General Public License for more details.
40 : : *
41 : : * You should have received a copy of the GNU Lesser General Public
42 : : * License along with this library; if not, write to the
43 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
44 : : * Boston, MA 02111-1307, USA.
45 : : */
46 : :
47 : : #ifdef HAVE_CONFIG_H
48 : : #include <config.h>
49 : : #endif
50 : :
51 : : #include <errno.h>
52 : : #include <stdlib.h>
53 : : #include <inttypes.h>
54 : : #include <string.h>
55 : :
56 : : #ifdef HAVE_ICONV
57 : : #include <iconv.h>
58 : : #endif
59 : :
60 : : #include <pulse/xmalloc.h>
61 : : #include <pulsecore/macro.h>
62 : :
63 : : #include "utf8.h"
64 : :
65 : : #define FILTER_CHAR '_'
66 : :
67 : : static inline pa_bool_t is_unicode_valid(uint32_t ch) {
68 : :
69 [ + - ]: 3 : if (ch >= 0x110000) /* End of unicode space */
70 : : return FALSE;
71 [ + - ]: 3 : if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */
72 : : return FALSE;
73 [ + - ]: 3 : if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */
74 : : return FALSE;
75 [ + - ]: 3 : if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */
76 : : return FALSE;
77 : :
78 : : return TRUE;
79 : : }
80 : :
81 : : static inline pa_bool_t is_continuation_char(uint8_t ch) {
82 [ - + ][ - + ]: 6 : if ((ch & 0xc0) != 0x80) /* 10xxxxxx */
[ + - ]
83 : : return FALSE;
84 : : return TRUE;
85 : : }
86 : :
87 : : static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) {
88 : 3 : *u_ch <<= 6;
89 : 0 : *u_ch |= ch & 0x3f;
90 : : }
91 : :
92 : 168 : static char* utf8_validate(const char *str, char *output) {
93 : 168 : uint32_t val = 0;
94 : 168 : uint32_t min = 0;
95 : : const uint8_t *p, *last;
96 : : int size;
97 : : uint8_t *o;
98 : :
99 [ + - ]: 168 : pa_assert(str);
100 : :
101 : : o = (uint8_t*) output;
102 [ + + ]: 3311 : for (p = (const uint8_t*) str; *p; p++) {
103 [ + + ]: 3144 : if (*p < 128) {
104 [ + + ]: 3134 : if (o)
105 : 98 : *o = *p;
106 : : } else {
107 : 10 : last = p;
108 : :
109 [ + + ]: 10 : if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */
110 : 3 : size = 2;
111 : 3 : min = 128;
112 : 3 : val = (uint32_t) (*p & 0x1e);
113 : 3 : goto ONE_REMAINING;
114 [ + + ]: 7 : } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/
115 : 1 : size = 3;
116 : 1 : min = (1 << 11);
117 : 1 : val = (uint32_t) (*p & 0x0f);
118 : 1 : goto TWO_REMAINING;
119 [ + + ]: 6 : } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */
120 : 2 : size = 4;
121 : 2 : min = (1 << 16);
122 : 2 : val = (uint32_t) (*p & 0x07);
123 : : } else
124 : : goto error;
125 : :
126 : 2 : p++;
127 [ - + ]: 2 : if (!is_continuation_char(*p))
128 : : goto error;
129 : 0 : merge_continuation_char(&val, *p);
130 : :
131 : : TWO_REMAINING:
132 : 1 : p++;
133 [ - + ]: 1 : if (!is_continuation_char(*p))
134 : : goto error;
135 : 0 : merge_continuation_char(&val, *p);
136 : :
137 : : ONE_REMAINING:
138 : 3 : p++;
139 [ + - ]: 3 : if (!is_continuation_char(*p))
140 : : goto error;
141 : 3 : merge_continuation_char(&val, *p);
142 : :
143 [ + - ]: 3 : if (val < min)
144 : : goto error;
145 : :
146 [ + - ]: 3 : if (!is_unicode_valid(val))
147 : : goto error;
148 : :
149 [ + + ]: 3 : if (o) {
150 : 2 : memcpy(o, last, (size_t) size);
151 : 2 : o += size;
152 : : }
153 : :
154 : 3 : continue;
155 : :
156 : : error:
157 [ + + ]: 7 : if (o) {
158 : 6 : *o = FILTER_CHAR;
159 : 6 : p = last; /* We retry at the next character */
160 : : } else
161 : : goto failure;
162 : : }
163 : :
164 [ + + ]: 3140 : if (o)
165 : 104 : o++;
166 : : }
167 : :
168 [ + + ]: 167 : if (o) {
169 : 5 : *o = '\0';
170 : 168 : return output;
171 : : }
172 : :
173 : : return (char*) str;
174 : :
175 : : failure:
176 : : return NULL;
177 : : }
178 : :
179 : 163 : char* pa_utf8_valid (const char *str) {
180 : 163 : return utf8_validate(str, NULL);
181 : : }
182 : :
183 : 5 : char* pa_utf8_filter (const char *str) {
184 : : char *new_str;
185 : :
186 [ - + ]: 5 : pa_assert(str);
187 : 5 : new_str = pa_xmalloc(strlen(str) + 1);
188 : 5 : return utf8_validate(str, new_str);
189 : : }
190 : :
191 : : #ifdef HAVE_ICONV
192 : :
193 : 87 : static char* iconv_simple(const char *str, const char *to, const char *from) {
194 : : char *new_str;
195 : : size_t len, inlen;
196 : : iconv_t cd;
197 : : ICONV_CONST char *inbuf;
198 : : char *outbuf;
199 : : size_t res, inbytes, outbytes;
200 : :
201 [ - + ]: 87 : pa_assert(str);
202 [ - + ]: 87 : pa_assert(to);
203 [ - + ]: 87 : pa_assert(from);
204 : :
205 : 87 : cd = iconv_open(to, from);
206 [ + - ]: 88 : if (cd == (iconv_t)-1)
207 : : return NULL;
208 : :
209 : 88 : inlen = len = strlen(str) + 1;
210 : 88 : new_str = pa_xmalloc(len);
211 : :
212 : : for (;;) {
213 : 88 : inbuf = (ICONV_CONST char*) str; /* Brain dead prototype for iconv() */
214 : 88 : inbytes = inlen;
215 : 88 : outbuf = new_str;
216 : 88 : outbytes = len;
217 : :
218 : 88 : res = iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes);
219 : :
220 [ - + ]: 88 : if (res != (size_t)-1)
221 : : break;
222 : :
223 [ # # ]: 0 : if (errno != E2BIG) {
224 : 0 : pa_xfree(new_str);
225 : 0 : new_str = NULL;
226 : 0 : break;
227 : : }
228 : :
229 [ # # ]: 0 : pa_assert(inbytes != 0);
230 : :
231 : 0 : len += inbytes;
232 : 0 : new_str = pa_xrealloc(new_str, len);
233 : 0 : }
234 : :
235 : 88 : iconv_close(cd);
236 : :
237 : 88 : return new_str;
238 : : }
239 : :
240 : 87 : char* pa_utf8_to_locale (const char *str) {
241 : 87 : return iconv_simple(str, "", "UTF-8");
242 : : }
243 : :
244 : 0 : char* pa_locale_to_utf8 (const char *str) {
245 : 0 : return iconv_simple(str, "UTF-8", "");
246 : : }
247 : :
248 : : #else
249 : :
250 : : char* pa_utf8_to_locale (const char *str) {
251 : : pa_assert(str);
252 : :
253 : : return pa_ascii_filter(str);
254 : : }
255 : :
256 : : char* pa_locale_to_utf8 (const char *str) {
257 : : pa_assert(str);
258 : :
259 : : if (pa_utf8_valid(str))
260 : : return pa_xstrdup(str);
261 : :
262 : : return NULL;
263 : : }
264 : :
265 : : #endif
266 : :
267 : 110 : char *pa_ascii_valid(const char *str) {
268 : : const char *p;
269 [ + - ]: 110 : pa_assert(str);
270 : :
271 [ + + ]: 1324 : for (p = str; *p; p++)
272 [ + - ]: 1214 : if ((unsigned char) *p >= 128)
273 : : return NULL;
274 : :
275 : : return (char*) str;
276 : : }
277 : :
278 : 0 : char *pa_ascii_filter(const char *str) {
279 : : char *r, *s, *d;
280 [ # # ]: 0 : pa_assert(str);
281 : :
282 : 0 : r = pa_xstrdup(str);
283 : :
284 [ # # ]: 0 : for (s = r, d = r; *s; s++)
285 [ # # ]: 0 : if ((unsigned char) *s < 128)
286 : 0 : *(d++) = *s;
287 : :
288 : 0 : *d = 0;
289 : :
290 : 0 : return r;
291 : : }
|