svn merge -r41266:41287 ^/trunk/blender
[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 char *BLI_strncpy_utf8(char *dst, const char *src, size_t maxncpy)
167 {
168         char *dst_r= dst;
169         size_t utf8_size;
170
171         /* note: currently we dont attempt to deal with invalid utf8 chars */
172
173         while(*src != '\0' && (utf8_size= utf8_skip_data[*src]) < maxncpy) {
174                 maxncpy -= utf8_size;
175                 switch(utf8_size) {
176                         case 6: *dst ++ = *src ++;
177                         case 5: *dst ++ = *src ++;
178                         case 4: *dst ++ = *src ++;
179                         case 3: *dst ++ = *src ++;
180                         case 2: *dst ++ = *src ++;
181                         case 1: *dst ++ = *src ++;
182                 }
183         }
184         *dst= '\0';
185         return dst_r;
186 }
187
188
189 /* --------------------------------------------------------------------------*/
190 /* wchar_t / utf8 functions  */
191
192 size_t BLI_strncpy_wchar_as_utf8(char *dst, const wchar_t *src, const size_t maxcpy)
193 {
194         size_t len = 0;
195         while(*src && len < maxcpy) { /* XXX can still run over the buffer because utf8 size isnt known :| */
196                 len += BLI_str_utf8_from_unicode(*src++, dst+len);
197         }
198
199         dst[len]= '\0';
200
201         return len;
202 }
203
204 /* wchar len in utf8 */
205 size_t BLI_wstrlen_utf8(const wchar_t *src)
206 {
207         size_t len = 0;
208
209         while(*src) {
210                 len += BLI_str_utf8_from_unicode(*src++, NULL);
211         }
212
213         return len;
214 }
215
216 // utf8slen
217 size_t BLI_strlen_utf8(const char *strc)
218 {
219         int len=0;
220
221         while(*strc) {
222                 if ((*strc & 0xe0) == 0xc0) {
223                         if((strc[1] & 0x80) && (strc[1] & 0x40) == 0x00)
224                                 strc++;
225                 } else if ((*strc & 0xf0) == 0xe0) {
226                         if((strc[1] & strc[2] & 0x80) && ((strc[1] | strc[2]) & 0x40) == 0x00)
227                                 strc += 2;
228                 } else if ((*strc & 0xf8) == 0xf0) {
229                         if((strc[1] & strc[2] & strc[3] & 0x80) && ((strc[1] | strc[2] | strc[3]) & 0x40) == 0x00)
230                                 strc += 3;
231                 }
232
233                 strc++;
234                 len++;
235         }
236
237         return len;
238 }
239
240 size_t BLI_strncpy_wchar_from_utf8(wchar_t *dst_w, const char *src_c, const size_t maxcpy)
241 {
242         int len=0;
243
244         if(dst_w==NULL || src_c==NULL) return(0);
245
246         while(*src_c && len < maxcpy) {
247                 size_t step= 0;
248                 unsigned int unicode= BLI_str_utf8_as_unicode_and_size(src_c, &step);
249                 if (unicode != BLI_UTF8_ERR) {
250                         *dst_w= (wchar_t)unicode;
251                         src_c += step;
252                 }
253                 else {
254                         *dst_w = '?';
255                         src_c= BLI_str_find_next_char_utf8(src_c, NULL);
256                 }
257                 dst_w++;
258                 len++;
259         }
260         return len;
261 }
262
263 /* end wchar_t / utf8 functions  */
264 /* --------------------------------------------------------------------------*/
265
266 /* copied from glib's gutf8.c */
267
268 /* note, glib uses unsigned int for unicode, best we do the same,
269  * though we dont typedef it - campbell */
270
271 #define UTF8_COMPUTE(Char, Mask, Len)                                         \
272         if (Char < 128) {                                                         \
273                 Len = 1;                                                              \
274                 Mask = 0x7f;                                                          \
275         }                                                                         \
276         else if ((Char & 0xe0) == 0xc0) {                                         \
277                 Len = 2;                                                              \
278                 Mask = 0x1f;                                                          \
279         }                                                                         \
280         else if ((Char & 0xf0) == 0xe0) {                                         \
281                 Len = 3;                                                              \
282                 Mask = 0x0f;                                                          \
283         }                                                                         \
284         else if ((Char & 0xf8) == 0xf0) {                                         \
285                 Len = 4;                                                              \
286                 Mask = 0x07;                                                          \
287         }                                                                         \
288         else if ((Char & 0xfc) == 0xf8) {                                         \
289                 Len = 5;                                                              \
290                 Mask = 0x03;                                                          \
291         }                                                                         \
292         else if ((Char & 0xfe) == 0xfc) {                                         \
293                 Len = 6;                                                              \
294                 Mask = 0x01;                                                          \
295         }                                                                         \
296         else {                                                                    \
297                 Len = -1;                                                             \
298         }
299
300 /* same as glib define but added an 'Err' arg */
301 #define UTF8_GET(Result, Chars, Count, Mask, Len, Err)                        \
302         (Result) = (Chars)[0] & (Mask);                                           \
303         for ((Count) = 1; (Count) < (Len); ++(Count)) {                           \
304                 if (((Chars)[(Count)] & 0xc0) != 0x80) {                              \
305                         (Result) = Err;                                                   \
306                         break;                                                            \
307                 }                                                                     \
308                 (Result) <<= 6;                                                       \
309                 (Result) |= ((Chars)[(Count)] & 0x3f);                                \
310         }
311
312
313 /* uses glib functions but not from glib */
314 /* gets the size of a single utf8 char */
315 int BLI_str_utf8_size(const char *p)
316 {
317         int mask = 0, len;
318     unsigned char c = (unsigned char) *p;
319
320     UTF8_COMPUTE (c, mask, len);
321
322         (void)mask; /* quiet warning */
323
324         return len;
325 }
326
327 /* was g_utf8_get_char */
328 /**
329  * BLI_str_utf8_as_unicode:
330  * @p: a pointer to Unicode character encoded as UTF-8
331  *
332  * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
333  * If @p does not point to a valid UTF-8 encoded character, results are
334  * undefined. If you are not sure that the bytes are complete
335  * valid Unicode characters, you should use g_utf8_get_char_validated()
336  * instead.
337  *
338  * Return value: the resulting character
339  **/
340 unsigned int BLI_str_utf8_as_unicode(const char *p)
341 {
342   int i, mask = 0, len;
343   unsigned int result;
344   unsigned char c = (unsigned char) *p;
345
346   UTF8_COMPUTE (c, mask, len);
347   if (len == -1)
348     return BLI_UTF8_ERR;
349   UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
350
351   return result;
352 }
353
354 /* varient that increments the length */
355 unsigned int BLI_str_utf8_as_unicode_and_size(const char *p, size_t *index)
356 {
357         int i, mask = 0, len;
358         unsigned int result;
359         unsigned char c = (unsigned char) *p;
360
361         UTF8_COMPUTE (c, mask, len);
362         if (len == -1)
363                 return BLI_UTF8_ERR;
364         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
365         *index += len;
366         return result;
367 }
368
369 /* another varient that steps over the index,
370  * note, currently this also falls back to latin1 for text drawing. */
371 unsigned int BLI_str_utf8_as_unicode_step(const char *p, size_t *index)
372 {
373         int i, mask = 0, len;
374         unsigned int result;
375         unsigned char c;
376
377         p += *index;
378         c= (unsigned char) *p;
379
380         UTF8_COMPUTE (c, mask, len);
381         if (len == -1) {
382                 /* when called with NULL end, result will never be NULL,
383                  * checks for a NULL character */
384                 char *p_next= BLI_str_find_next_char_utf8(p, NULL);
385                 /* will never return the same pointer unless '\0',
386                  * eternal loop is prevented */
387                 *index += (size_t)(p_next - p);
388                 return BLI_UTF8_ERR;
389         }
390
391         /* this is tricky since there are a few ways we can bail out of bad unicode
392          * values, 3 possible solutions. */
393 #if 0
394         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
395 #elif 1
396         /* WARNING: this is NOT part of glib, or supported by similar functions.
397          * this is added for text drawing because some filepaths can have latin1
398          * characters */
399         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
400         if(result == BLI_UTF8_ERR) {
401                 len= 1;
402                 result= *p;
403         }
404         /* end warning! */
405 #else
406         /* without a fallback like '?', text drawing will stop on this value */
407         UTF8_GET (result, p, i, mask, len, '?');
408 #endif
409
410         *index += len;
411         return result;
412 }
413
414 /* was g_unichar_to_utf8 */
415 /**
416  * BLI_str_utf8_from_unicode:
417  * @c: a Unicode character code
418  * @outbuf: output buffer, must have at least 6 bytes of space.
419  *       If %NULL, the length will be computed and returned
420  *       and nothing will be written to @outbuf.
421  *
422  * Converts a single character to UTF-8.
423  *
424  * Return value: number of bytes written
425  **/
426 size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf)
427 {
428         /* If this gets modified, also update the copy in g_string_insert_unichar() */
429         unsigned int len = 0;
430         int first;
431         int i;
432
433         if (c < 0x80) {
434                 first = 0;
435                 len = 1;
436         }
437         else if (c < 0x800) {
438                 first = 0xc0;
439                 len = 2;
440         }
441         else if (c < 0x10000) {
442                 first = 0xe0;
443                 len = 3;
444         }
445         else if (c < 0x200000) {
446                 first = 0xf0;
447                 len = 4;
448         }
449         else if (c < 0x4000000) {
450                 first = 0xf8;
451                 len = 5;
452         }
453         else {
454                 first = 0xfc;
455                 len = 6;
456         }
457
458         if (outbuf) {
459                 for (i = len - 1; i > 0; --i) {
460                         outbuf[i] = (c & 0x3f) | 0x80;
461                         c >>= 6;
462                 }
463                 outbuf[0] = c | first;
464         }
465
466         return len;
467 }
468
469 /* was g_utf8_find_prev_char */
470 /**
471  * BLI_str_find_prev_char_utf8:
472  * @str: pointer to the beginning of a UTF-8 encoded string
473  * @p: pointer to some position within @str
474  *
475  * Given a position @p with a UTF-8 encoded string @str, find the start
476  * of the previous UTF-8 character starting before @p. Returns %NULL if no
477  * UTF-8 characters are present in @str before @p.
478  *
479  * @p does not have to be at the beginning of a UTF-8 character. No check
480  * is made to see if the character found is actually valid other than
481  * it starts with an appropriate byte.
482  *
483  * Return value: a pointer to the found character or %NULL.
484  **/
485 char * BLI_str_find_prev_char_utf8(const char *str, const char *p)
486 {
487         for (--p; p >= str; --p) {
488                 if ((*p & 0xc0) != 0x80) {
489                         return (char *)p;
490                 }
491         }
492         return NULL;
493 }
494
495 /* was g_utf8_find_next_char */
496 /**
497  * BLI_str_find_next_char_utf8:
498  * @p: a pointer to a position within a UTF-8 encoded string
499  * @end: a pointer to the byte following the end of the string,
500  * or %NULL to indicate that the string is nul-terminated.
501  *
502  * Finds the start of the next UTF-8 character in the string after @p.
503  *
504  * @p does not have to be at the beginning of a UTF-8 character. No check
505  * is made to see if the character found is actually valid other than
506  * it starts with an appropriate byte.
507  *
508  * Return value: a pointer to the found character or %NULL
509  **/
510 char *BLI_str_find_next_char_utf8(const char *p, const char *end)
511 {
512         if (*p) {
513                 if (end) {
514                         for (++p; p < end && (*p & 0xc0) == 0x80; ++p) {
515                                 /* do nothing */
516                         }
517                 }
518                 else {
519                         for (++p; (*p & 0xc0) == 0x80; ++p) {
520                                 /* do nothing */
521                         }
522                 }
523         }
524         return (p == end) ? NULL : (char *)p;
525 }
526
527 /* was g_utf8_prev_char */
528 /**
529  * BLI_str_prev_char_utf8:
530  * @p: a pointer to a position within a UTF-8 encoded string
531  *
532  * Finds the previous UTF-8 character in the string before @p.
533  *
534  * @p does not have to be at the beginning of a UTF-8 character. No check
535  * is made to see if the character found is actually valid other than
536  * it starts with an appropriate byte. If @p might be the first
537  * character of the string, you must use g_utf8_find_prev_char() instead.
538  *
539  * Return value: a pointer to the found character.
540  **/
541 char *BLI_str_prev_char_utf8(const char *p)
542 {
543         while (1) {
544                 p--;
545                 if ((*p & 0xc0) != 0x80) {
546                         return (char *)p;
547                 }
548         }
549 }
550 /* end glib copy */