9c7829dbcb6a1410b1269312c03c092fc4829de9
[blender.git] / source / blender / blenlib / intern / string_utf8.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * Code from gutf8.c Copyright (C) 1999 Tom Tromey
20  *                   Copyright (C) 2000 Red Hat, Inc.
21  * All rights reserved.
22  *
23  * Contributor(s): Campbell Barton.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  */
28
29  /** \file blender/blenlib/intern/string_utf8.c
30   *  \ingroup bli
31   */
32
33 #include <string.h>
34 #include <wchar.h>
35 #include <wctype.h>
36
37 #include "BLI_string_utf8.h"
38
39 /* from libswish3, originally called u8_isvalid(),
40  * modified to return the index of the bad character (byte index not utf).
41  * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
42
43 /* based on the valid_utf8 routine from the PCRE library by Philip Hazel
44  *
45  * length is in bytes, since without knowing whether the string is valid
46  * it's hard to know how many characters there are! */
47
48 static const char trailingBytesForUTF8[256] = {
49         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
57 };
58
59 int BLI_utf8_invalid_byte(const char *str, int length)
60 {
61         const unsigned char *p, *pend = (unsigned char *)str + length;
62         unsigned char c;
63         int ab;
64
65         for (p = (unsigned char *)str; p < pend; p++) {
66                 c = *p;
67                 if (c < 128)
68                         continue;
69                 if ((c & 0xc0) != 0xc0)
70                         goto utf8_error;
71                 ab = trailingBytesForUTF8[c];
72                 if (length < ab)
73                         goto utf8_error;
74                 length -= ab;
75
76                 p++;
77                 /* Check top bits in the second byte */
78                 if ((*p & 0xc0) != 0x80)
79                         goto utf8_error;
80
81                 /* Check for overlong sequences for each different length */
82                 switch (ab) {
83                         /* Check for xx00 000x */
84                 case 1:
85                         if ((c & 0x3e) == 0) goto utf8_error;
86                         continue;   /* We know there aren't any more bytes to check */
87
88                         /* Check for 1110 0000, xx0x xxxx */
89                 case 2:
90                         if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
91                         break;
92
93                         /* Check for 1111 0000, xx00 xxxx */
94                 case 3:
95                         if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
96                         break;
97
98                         /* Check for 1111 1000, xx00 0xxx */
99                 case 4:
100                         if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
101                         break;
102
103                         /* Check for leading 0xfe or 0xff,
104                          * and then for 1111 1100, xx00 00xx */
105                 case 5:
106                         if (c == 0xfe || c == 0xff ||
107                                 (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error;
108                         break;
109                 }
110
111                 /* Check for valid bytes after the 2nd, if any; all must start 10 */
112                 while (--ab > 0) {
113                         if ((*(p+1) & 0xc0) != 0x80) goto utf8_error;
114                         p++; /* do this after so we get usable offset - campbell */
115                 }
116         }
117
118         return -1;
119
120 utf8_error:
121
122         return (int)((char *)p - (char *)str) - 1;
123 }
124
125 int BLI_utf8_invalid_strip(char *str, int length)
126 {
127         int bad_char, tot = 0;
128
129         while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) {
130                 str += bad_char;
131                 length -= bad_char;
132
133                 if (length == 0) {
134                         /* last character bad, strip it */
135                         *str = '\0';
136                         tot++;
137                         break;
138                 }
139                 else {
140                         /* strip, keep looking */
141                         memmove(str, str + 1, length);
142                         tot++;
143                 }
144         }
145
146         return tot;
147 }
148
149
150 /* compatible with BLI_strncpy, but esnure no partial utf8 chars */
151
152 /* array copied from glib's gutf8.c,
153  * note: this looks to be at odd's with 'trailingBytesForUTF8',
154  * need to find out what gives here! - campbell */
155 static const size_t utf8_skip_data[256] = {
156     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
157     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
158     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
159     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
160     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
161     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
162     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
163     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
164 };
165
166 #define BLI_STR_UTF8_CPY(dst, src, maxncpy)                                   \
167         {                                                                         \
168                 size_t utf8_size;                                                     \
169                 while (*src != '\0' && (utf8_size = utf8_skip_data[*src]) < maxncpy) {\
170                         maxncpy -= utf8_size;                                             \
171                         switch (utf8_size) {                                              \
172                                 case 6: *dst ++ = *src ++;                                    \
173                                 case 5: *dst ++ = *src ++;                                    \
174                                 case 4: *dst ++ = *src ++;                                    \
175                                 case 3: *dst ++ = *src ++;                                    \
176                                 case 2: *dst ++ = *src ++;                                    \
177                                 case 1: *dst ++ = *src ++;                                    \
178                         }                                                                 \
179                 }                                                                     \
180                 *dst = '\0';                                                          \
181         } (void)0
182
183 char *BLI_strncpy_utf8(char *dst, const char *src, size_t maxncpy)
184 {
185         char *dst_r = dst;
186
187         /* note: currently we don't attempt to deal with invalid utf8 chars */
188         BLI_STR_UTF8_CPY(dst, src, maxncpy);
189
190         return dst_r;
191 }
192
193 char *BLI_strncat_utf8(char *dst, const char *src, size_t maxncpy)
194 {
195         while (*dst && maxncpy > 0) {
196                 dst++;
197                 maxncpy--;
198         }
199
200         BLI_STR_UTF8_CPY(dst, src, maxncpy);
201
202         return dst;
203 }
204
205 #undef BLI_STR_UTF8_CPY
206
207 /* --------------------------------------------------------------------------*/
208 /* wchar_t / utf8 functions  */
209
210 size_t BLI_strncpy_wchar_as_utf8(char *dst, const wchar_t *src, const size_t maxcpy)
211 {
212         size_t len = 0;
213         while (*src && len < maxcpy) { /* XXX can still run over the buffer because utf8 size isn't known :| */
214                 len += BLI_str_utf8_from_unicode(*src++, dst + len);
215         }
216
217         dst[len] = '\0';
218
219         return len;
220 }
221
222 /* wchar len in utf8 */
223 size_t BLI_wstrlen_utf8(const wchar_t *src)
224 {
225         size_t len = 0;
226
227         while (*src) {
228                 len += BLI_str_utf8_from_unicode(*src++, NULL);
229         }
230
231         return len;
232 }
233
234 /* size of UTF-8 character in bytes */
235 size_t BLI_strlen_utf8_char(const char *strc)
236 {
237         if ((*strc & 0xe0) == 0xc0) {
238                 if ((strc[1] & 0x80) && (strc[1] & 0x40) == 0x00)
239                         return 2;
240         }
241         else if ((*strc & 0xf0) == 0xe0) {
242                 if ((strc[1] & strc[2] & 0x80) && ((strc[1] | strc[2]) & 0x40) == 0x00)
243                         return 3;
244         }
245         else if ((*strc & 0xf8) == 0xf0) {
246                 if ((strc[1] & strc[2] & strc[3] & 0x80) && ((strc[1] | strc[2] | strc[3]) & 0x40) == 0x00)
247                         return 4;
248         }
249
250         return 1;
251 }
252
253 size_t BLI_strlen_utf8(const char *strc)
254 {
255         int len;
256
257         for (len = 0; *strc; len++)
258                 strc += BLI_strlen_utf8_char(strc);
259
260         return len;
261 }
262
263 size_t BLI_strlen_range_utf8(const char *start, const char *end)
264 {
265         const char *strc = start;
266         int len;
267
268         for (len = 0; strc < end; len++)
269                 strc += BLI_strlen_utf8_char(strc);
270
271         return len;
272 }
273
274 size_t BLI_strncpy_wchar_from_utf8(wchar_t *dst_w, const char *src_c, const size_t maxcpy)
275 {
276         int len = 0;
277
278         if (dst_w == NULL || src_c == NULL) {
279                 return 0;
280         }
281
282         while (*src_c && len < maxcpy) {
283                 size_t step = 0;
284                 unsigned int unicode = BLI_str_utf8_as_unicode_and_size(src_c, &step);
285                 if (unicode != BLI_UTF8_ERR) {
286                         *dst_w = (wchar_t)unicode;
287                         src_c += step;
288                 }
289                 else {
290                         *dst_w = '?';
291                         src_c = BLI_str_find_next_char_utf8(src_c, NULL);
292                 }
293                 dst_w++;
294                 len++;
295         }
296         return len;
297 }
298
299 /* end wchar_t / utf8 functions  */
300 /* --------------------------------------------------------------------------*/
301
302 /* copied from glib's gutf8.c */
303
304 /* note, glib uses unsigned int for unicode, best we do the same,
305  * though we don't typedef it - campbell */
306
307 #define UTF8_COMPUTE(Char, Mask, Len)                                         \
308         if (Char < 128) {                                                         \
309                 Len = 1;                                                              \
310                 Mask = 0x7f;                                                          \
311         }                                                                         \
312         else if ((Char & 0xe0) == 0xc0) {                                         \
313                 Len = 2;                                                              \
314                 Mask = 0x1f;                                                          \
315         }                                                                         \
316         else if ((Char & 0xf0) == 0xe0) {                                         \
317                 Len = 3;                                                              \
318                 Mask = 0x0f;                                                          \
319         }                                                                         \
320         else if ((Char & 0xf8) == 0xf0) {                                         \
321                 Len = 4;                                                              \
322                 Mask = 0x07;                                                          \
323         }                                                                         \
324         else if ((Char & 0xfc) == 0xf8) {                                         \
325                 Len = 5;                                                              \
326                 Mask = 0x03;                                                          \
327         }                                                                         \
328         else if ((Char & 0xfe) == 0xfc) {                                         \
329                 Len = 6;                                                              \
330                 Mask = 0x01;                                                          \
331         }                                                                         \
332         else {                                                                    \
333                 Len = -1;                                                             \
334         } (void)0
335
336 /* same as glib define but added an 'Err' arg */
337 #define UTF8_GET(Result, Chars, Count, Mask, Len, Err)                        \
338         (Result) = (Chars)[0] & (Mask);                                           \
339         for ((Count) = 1; (Count) < (Len); ++(Count)) {                           \
340                 if (((Chars)[(Count)] & 0xc0) != 0x80) {                              \
341                         (Result) = Err;                                                   \
342                         break;                                                            \
343                 }                                                                     \
344                 (Result) <<= 6;                                                       \
345                 (Result) |= ((Chars)[(Count)] & 0x3f);                                \
346         } (void)0
347
348
349 /* uses glib functions but not from glib */
350 /* gets the size of a single utf8 char */
351 int BLI_str_utf8_size(const char *p)
352 {
353         int mask = 0, len;
354         unsigned char c = (unsigned char) *p;
355
356         UTF8_COMPUTE (c, mask, len);
357
358         (void)mask; /* quiet warning */
359
360         return len;
361 }
362
363 /* was g_utf8_get_char */
364 /**
365  * BLI_str_utf8_as_unicode:
366  * @p a pointer to Unicode character encoded as UTF-8
367  *
368  * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
369  * If @p does not point to a valid UTF-8 encoded character, results are
370  * undefined. If you are not sure that the bytes are complete
371  * valid Unicode characters, you should use g_utf8_get_char_validated()
372  * instead.
373  *
374  * Return value: the resulting character
375  **/
376 unsigned int BLI_str_utf8_as_unicode(const char *p)
377 {
378         int i, mask = 0, len;
379         unsigned int result;
380         unsigned char c = (unsigned char) *p;
381
382         UTF8_COMPUTE (c, mask, len);
383         if (len == -1)
384                 return BLI_UTF8_ERR;
385         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
386
387         return result;
388 }
389
390 /* variant that increments the length */
391 unsigned int BLI_str_utf8_as_unicode_and_size(const char *p, size_t *index)
392 {
393         int i, mask = 0, len;
394         unsigned int result;
395         unsigned char c = (unsigned char) *p;
396
397         UTF8_COMPUTE (c, mask, len);
398         if (len == -1)
399                 return BLI_UTF8_ERR;
400         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
401         *index += len;
402         return result;
403 }
404
405 /* another variant that steps over the index,
406  * note, currently this also falls back to latin1 for text drawing. */
407 unsigned int BLI_str_utf8_as_unicode_step(const char *p, size_t *index)
408 {
409         int i, mask = 0, len;
410         unsigned int result;
411         unsigned char c;
412
413         p += *index;
414         c = (unsigned char) *p;
415
416         UTF8_COMPUTE (c, mask, len);
417         if (len == -1) {
418                 /* when called with NULL end, result will never be NULL,
419                  * checks for a NULL character */
420                 char *p_next = BLI_str_find_next_char_utf8(p, NULL);
421                 /* will never return the same pointer unless '\0',
422                  * eternal loop is prevented */
423                 *index += (size_t)(p_next - p);
424                 return BLI_UTF8_ERR;
425         }
426
427         /* this is tricky since there are a few ways we can bail out of bad unicode
428          * values, 3 possible solutions. */
429 #if 0
430         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
431 #elif 1
432         /* WARNING: this is NOT part of glib, or supported by similar functions.
433          * this is added for text drawing because some filepaths can have latin1
434          * characters */
435         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
436         if (result == BLI_UTF8_ERR) {
437                 len = 1;
438                 result = *p;
439         }
440         /* end warning! */
441 #else
442         /* without a fallback like '?', text drawing will stop on this value */
443         UTF8_GET (result, p, i, mask, len, '?');
444 #endif
445
446         *index += len;
447         return result;
448 }
449
450 /* was g_unichar_to_utf8 */
451 /**
452  * BLI_str_utf8_from_unicode:
453  * @c a Unicode character code
454  * \param outbuf output buffer, must have at least 6 bytes of space.
455  *       If %NULL, the length will be computed and returned
456  *       and nothing will be written to outbuf.
457  *
458  * Converts a single character to UTF-8.
459  *
460  * Return value: number of bytes written
461  **/
462 size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf)
463 {
464         /* If this gets modified, also update the copy in g_string_insert_unichar() */
465         unsigned int len = 0;
466         int first;
467         int i;
468
469         if (c < 0x80) {
470                 first = 0;
471                 len = 1;
472         }
473         else if (c < 0x800) {
474                 first = 0xc0;
475                 len = 2;
476         }
477         else if (c < 0x10000) {
478                 first = 0xe0;
479                 len = 3;
480         }
481         else if (c < 0x200000) {
482                 first = 0xf0;
483                 len = 4;
484         }
485         else if (c < 0x4000000) {
486                 first = 0xf8;
487                 len = 5;
488         }
489         else {
490                 first = 0xfc;
491                 len = 6;
492         }
493
494         if (outbuf) {
495                 for (i = len - 1; i > 0; --i) {
496                         outbuf[i] = (c & 0x3f) | 0x80;
497                         c >>= 6;
498                 }
499                 outbuf[0] = c | first;
500         }
501
502         return len;
503 }
504
505 /* was g_utf8_find_prev_char */
506 /**
507  * BLI_str_find_prev_char_utf8:
508  * @str: pointer to the beginning of a UTF-8 encoded string
509  * @p pointer to some position within @str
510  *
511  * Given a position @p with a UTF-8 encoded string @str, find the start
512  * of the previous UTF-8 character starting before. @p Returns %NULL if no
513  * UTF-8 characters are present in @str before @p
514  *
515  * @p does not have to be at the beginning of a UTF-8 character. No check
516  * is made to see if the character found is actually valid other than
517  * it starts with an appropriate byte.
518  *
519  * Return value: a pointer to the found character or %NULL.
520  **/
521 char * BLI_str_find_prev_char_utf8(const char *str, const char *p)
522 {
523         for (--p; p >= str; --p) {
524                 if ((*p & 0xc0) != 0x80) {
525                         return (char *)p;
526                 }
527         }
528         return NULL;
529 }
530
531 /* was g_utf8_find_next_char */
532 /**
533  * BLI_str_find_next_char_utf8:
534  * @p a pointer to a position within a UTF-8 encoded string
535  * @end a pointer to the byte following the end of the string,
536  * or %NULL to indicate that the string is nul-terminated.
537  *
538  * Finds the start of the next UTF-8 character in the string after @p
539  *
540  * @p does not have to be at the beginning of a UTF-8 character. No check
541  * is made to see if the character found is actually valid other than
542  * it starts with an appropriate byte.
543  *
544  * Return value: a pointer to the found character or %NULL
545  **/
546 char *BLI_str_find_next_char_utf8(const char *p, const char *end)
547 {
548         if (*p) {
549                 if (end) {
550                         for (++p; p < end && (*p & 0xc0) == 0x80; ++p) {
551                                 /* do nothing */
552                         }
553                 }
554                 else {
555                         for (++p; (*p & 0xc0) == 0x80; ++p) {
556                                 /* do nothing */
557                         }
558                 }
559         }
560         return (p == end) ? NULL : (char *)p;
561 }
562
563 /* was g_utf8_prev_char */
564 /**
565  * BLI_str_prev_char_utf8:
566  * @p a pointer to a position within a UTF-8 encoded string
567  *
568  * Finds the previous UTF-8 character in the string before @p
569  *
570  * @p does not have to be at the beginning of a UTF-8 character. No check
571  * is made to see if the character found is actually valid other than
572  * it starts with an appropriate byte. If @p might be the first
573  * character of the string, you must use g_utf8_find_prev_char() instead.
574  *
575  * Return value: a pointer to the found character.
576  **/
577 char *BLI_str_prev_char_utf8(const char *p)
578 {
579         while (1) {
580                 p--;
581                 if ((*p & 0xc0) != 0x80) {
582                         return (char *)p;
583                 }
584         }
585 }
586 /* end glib copy */