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