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