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