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