Merge branch 'blender-v2.81-release'
[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)) {
81       /* Those three values are not allowed in utf8 string. */
82       goto utf8_error;
83     }
84     if (c < 128) {
85       continue;
86     }
87     if ((c & 0xc0) != 0xc0) {
88       goto utf8_error;
89     }
90
91     /* Note that since we always increase p (and decrease length) by one byte in main loop,
92      * we only add/subtract extra utf8 bytes in code below
93      * (ab number, aka number of bytes remaining in the utf8 sequence after the initial one). */
94     ab = (int)utf8_skip_data[c] - 1;
95     if (length <= ab) {
96       goto utf8_error;
97     }
98
99     /* Check top bits in the second byte */
100     p++;
101     length--;
102     if ((*p & 0xc0) != 0x80) {
103       goto utf8_error;
104     }
105
106     /* Check for overlong sequences for each different length */
107     switch (ab) {
108       case 1:
109         /* Check for xx00 000x */
110         if ((c & 0x3e) == 0) {
111           goto utf8_error;
112         }
113         continue; /* We know there aren't any more bytes to check */
114
115       case 2:
116         /* Check for 1110 0000, xx0x xxxx */
117         if (c == 0xe0 && (*p & 0x20) == 0) {
118           goto utf8_error;
119         }
120         /* Some special cases, see section 5 of utf-8 decoder stress-test by Markus Kuhn
121          * (https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt). */
122         /* From section 5.1 (and 5.2) */
123         if (c == 0xed) {
124           if (*p == 0xa0 && *(p + 1) == 0x80) {
125             goto utf8_error;
126           }
127           if (*p == 0xad && *(p + 1) == 0xbf) {
128             goto utf8_error;
129           }
130           if (*p == 0xae && *(p + 1) == 0x80) {
131             goto utf8_error;
132           }
133           if (*p == 0xaf && *(p + 1) == 0xbf) {
134             goto utf8_error;
135           }
136           if (*p == 0xb0 && *(p + 1) == 0x80) {
137             goto utf8_error;
138           }
139           if (*p == 0xbe && *(p + 1) == 0x80) {
140             goto utf8_error;
141           }
142           if (*p == 0xbf && *(p + 1) == 0xbf) {
143             goto utf8_error;
144           }
145         }
146         /* From section 5.3 */
147         if (c == 0xef) {
148           if (*p == 0xbf && *(p + 1) == 0xbe) {
149             goto utf8_error;
150           }
151           if (*p == 0xbf && *(p + 1) == 0xbf) {
152             goto utf8_error;
153           }
154         }
155         break;
156
157       case 3:
158         /* Check for 1111 0000, xx00 xxxx */
159         if (c == 0xf0 && (*p & 0x30) == 0) {
160           goto utf8_error;
161         }
162         break;
163
164       case 4:
165         /* Check for 1111 1000, xx00 0xxx */
166         if (c == 0xf8 && (*p & 0x38) == 0) {
167           goto utf8_error;
168         }
169         break;
170
171       case 5:
172         /* Check for 1111 1100, xx00 00xx */
173         if (c == 0xfc && (*p & 0x3c) == 0) {
174           goto utf8_error;
175         }
176         break;
177     }
178
179     /* Check for valid bytes after the 2nd, if any; all must start 10 */
180     while (--ab > 0) {
181       p++;
182       length--;
183       if ((*p & 0xc0) != 0x80) {
184         goto utf8_error;
185       }
186     }
187   }
188
189   return -1;
190
191 utf8_error:
192
193   return ((const char *)perr - (const char *)str);
194 }
195
196 /**
197  * Remove any invalid utf-8 byte (taking into account multi-bytes sequence of course).
198  *
199  * \return number of stripped bytes.
200  */
201 int BLI_utf8_invalid_strip(char *str, size_t length)
202 {
203   ptrdiff_t bad_char;
204   int tot = 0;
205
206   BLI_assert(str[length] == '\0');
207
208   while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) {
209     str += bad_char;
210     length -= (size_t)(bad_char + 1);
211
212     if (length == 0) {
213       /* last character bad, strip it */
214       *str = '\0';
215       tot++;
216       break;
217     }
218     else {
219       /* strip, keep looking */
220       memmove(str, str + 1, length + 1); /* +1 for NULL char! */
221       tot++;
222     }
223   }
224
225   return tot;
226 }
227
228 /* compatible with BLI_strncpy, but esnure no partial utf8 chars */
229
230 #define BLI_STR_UTF8_CPY(dst, src, maxncpy) \
231   { \
232     size_t utf8_size; \
233     while (*src != '\0' && (utf8_size = utf8_skip_data[*src]) < maxncpy) { \
234       maxncpy -= utf8_size; \
235       switch (utf8_size) { \
236         case 6: \
237           *dst++ = *src++; \
238           ATTR_FALLTHROUGH; \
239         case 5: \
240           *dst++ = *src++; \
241           ATTR_FALLTHROUGH; \
242         case 4: \
243           *dst++ = *src++; \
244           ATTR_FALLTHROUGH; \
245         case 3: \
246           *dst++ = *src++; \
247           ATTR_FALLTHROUGH; \
248         case 2: \
249           *dst++ = *src++; \
250           ATTR_FALLTHROUGH; \
251         case 1: \
252           *dst++ = *src++; \
253       } \
254     } \
255     *dst = '\0'; \
256   } \
257   (void)0
258
259 char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy)
260 {
261   char *r_dst = dst;
262
263   BLI_assert(maxncpy != 0);
264
265 #ifdef DEBUG_STRSIZE
266   memset(dst, 0xff, sizeof(*dst) * maxncpy);
267 #endif
268
269   /* note: currently we don't attempt to deal with invalid utf8 chars */
270   BLI_STR_UTF8_CPY(dst, src, maxncpy);
271
272   return r_dst;
273 }
274
275 size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy)
276 {
277   char *r_dst = dst;
278
279   BLI_assert(maxncpy != 0);
280
281 #ifdef DEBUG_STRSIZE
282   memset(dst, 0xff, sizeof(*dst) * maxncpy);
283 #endif
284
285   /* note: currently we don't attempt to deal with invalid utf8 chars */
286   BLI_STR_UTF8_CPY(dst, src, maxncpy);
287
288   return (size_t)(dst - r_dst);
289 }
290
291 char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy)
292 {
293   while (*dst && maxncpy > 0) {
294     dst++;
295     maxncpy--;
296   }
297
298 #ifdef DEBUG_STRSIZE
299   memset(dst, 0xff, sizeof(*dst) * maxncpy);
300 #endif
301
302   BLI_STR_UTF8_CPY(dst, src, maxncpy);
303
304   return dst;
305 }
306
307 #undef BLI_STR_UTF8_CPY
308
309 /* --------------------------------------------------------------------------*/
310 /* wchar_t / utf8 functions  */
311
312 size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
313                                  const wchar_t *__restrict src,
314                                  const size_t maxncpy)
315 {
316   const size_t maxlen = maxncpy - 1;
317   /* 6 is max utf8 length of an unicode char. */
318   const int64_t maxlen_secured = (int64_t)maxlen - 6;
319   size_t len = 0;
320
321   BLI_assert(maxncpy != 0);
322
323 #ifdef DEBUG_STRSIZE
324   memset(dst, 0xff, sizeof(*dst) * maxncpy);
325 #endif
326
327   while (*src && len <= maxlen_secured) {
328     len += BLI_str_utf8_from_unicode((uint)*src++, dst + len);
329   }
330
331   /* We have to be more careful for the last six bytes,
332    * to avoid buffer overflow in case utf8-encoded char would be too long for our dst buffer. */
333   while (*src) {
334     char t[6];
335     size_t l = BLI_str_utf8_from_unicode((uint)*src++, t);
336     BLI_assert(l <= 6);
337     if (len + l > maxlen) {
338       break;
339     }
340     memcpy(dst + len, t, l);
341     len += l;
342   }
343
344   dst[len] = '\0';
345
346   return len;
347 }
348
349 /* wchar len in utf8 */
350 size_t BLI_wstrlen_utf8(const wchar_t *src)
351 {
352   size_t len = 0;
353
354   while (*src) {
355     len += BLI_str_utf8_from_unicode((uint)*src++, NULL);
356   }
357
358   return len;
359 }
360
361 size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes)
362 {
363   size_t len;
364   const char *strc_orig = strc;
365
366   for (len = 0; *strc; len++) {
367     strc += BLI_str_utf8_size_safe(strc);
368   }
369
370   *r_len_bytes = (size_t)(strc - strc_orig);
371   return len;
372 }
373
374 size_t BLI_strlen_utf8(const char *strc)
375 {
376   size_t len;
377
378   for (len = 0; *strc; len++) {
379     strc += BLI_str_utf8_size_safe(strc);
380   }
381
382   return len;
383 }
384
385 size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_bytes)
386 {
387   size_t len;
388   const char *strc_orig = strc;
389   const char *strc_end = strc + maxlen;
390
391   for (len = 0; *strc && strc < strc_end; len++) {
392     strc += BLI_str_utf8_size_safe(strc);
393   }
394
395   *r_len_bytes = (size_t)(strc - strc_orig);
396   return len;
397 }
398
399 /**
400  * \param strc: the string to measure the length.
401  * \param maxlen: the string length (in bytes)
402  * \return the unicode length (not in bytes!)
403  */
404 size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
405 {
406   size_t len;
407   const char *strc_end = strc + maxlen;
408
409   for (len = 0; *strc && strc < strc_end; len++) {
410     strc += BLI_str_utf8_size_safe(strc);
411   }
412
413   return len;
414 }
415
416 size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w,
417                                    const char *__restrict src_c,
418                                    const size_t maxncpy)
419 {
420   const size_t maxlen = maxncpy - 1;
421   size_t len = 0;
422
423   BLI_assert(maxncpy != 0);
424
425 #ifdef DEBUG_STRSIZE
426   memset(dst_w, 0xff, sizeof(*dst_w) * maxncpy);
427 #endif
428
429   while (*src_c && len != maxlen) {
430     size_t step = 0;
431     uint unicode = BLI_str_utf8_as_unicode_and_size(src_c, &step);
432     if (unicode != BLI_UTF8_ERR) {
433       *dst_w = (wchar_t)unicode;
434       src_c += step;
435     }
436     else {
437       *dst_w = '?';
438       src_c = BLI_str_find_next_char_utf8(src_c, NULL);
439     }
440     dst_w++;
441     len++;
442   }
443
444   *dst_w = 0;
445
446   return len;
447 }
448
449 /* end wchar_t / utf8 functions  */
450 /* --------------------------------------------------------------------------*/
451
452 /* count columns that character/string occupies, based on wcwidth.c */
453
454 int BLI_wcwidth(wchar_t ucs)
455 {
456   return mk_wcwidth(ucs);
457 }
458
459 int BLI_wcswidth(const wchar_t *pwcs, size_t n)
460 {
461   return mk_wcswidth(pwcs, n);
462 }
463
464 int BLI_str_utf8_char_width(const char *p)
465 {
466   uint unicode = BLI_str_utf8_as_unicode(p);
467   if (unicode == BLI_UTF8_ERR) {
468     return -1;
469   }
470
471   return BLI_wcwidth((wchar_t)unicode);
472 }
473
474 int BLI_str_utf8_char_width_safe(const char *p)
475 {
476   int columns;
477
478   uint unicode = BLI_str_utf8_as_unicode(p);
479   if (unicode == BLI_UTF8_ERR) {
480     return 1;
481   }
482
483   columns = BLI_wcwidth((wchar_t)unicode);
484
485   return (columns < 0) ? 1 : columns;
486 }
487
488 /* --------------------------------------------------------------------------*/
489
490 /* copied from glib's gutf8.c, added 'Err' arg */
491
492 /* note, glib uses uint for unicode, best we do the same,
493  * though we don't typedef it - campbell */
494
495 #define UTF8_COMPUTE(Char, Mask, Len, Err) \
496   if (Char < 128) { \
497     Len = 1; \
498     Mask = 0x7f; \
499   } \
500   else if ((Char & 0xe0) == 0xc0) { \
501     Len = 2; \
502     Mask = 0x1f; \
503   } \
504   else if ((Char & 0xf0) == 0xe0) { \
505     Len = 3; \
506     Mask = 0x0f; \
507   } \
508   else if ((Char & 0xf8) == 0xf0) { \
509     Len = 4; \
510     Mask = 0x07; \
511   } \
512   else if ((Char & 0xfc) == 0xf8) { \
513     Len = 5; \
514     Mask = 0x03; \
515   } \
516   else if ((Char & 0xfe) == 0xfc) { \
517     Len = 6; \
518     Mask = 0x01; \
519   } \
520   else { \
521     Len = Err; /* -1 is the typical error value or 1 to skip */ \
522   } \
523   (void)0
524
525 /* same as glib define but added an 'Err' arg */
526 #define UTF8_GET(Result, Chars, Count, Mask, Len, Err) \
527   (Result) = (Chars)[0] & (Mask); \
528   for ((Count) = 1; (Count) < (Len); ++(Count)) { \
529     if (((Chars)[(Count)] & 0xc0) != 0x80) { \
530       (Result) = Err; \
531       break; \
532     } \
533     (Result) <<= 6; \
534     (Result) |= ((Chars)[(Count)] & 0x3f); \
535   } \
536   (void)0
537
538 /* uses glib functions but not from glib */
539 /* gets the size of a single utf8 char */
540 int BLI_str_utf8_size(const char *p)
541 {
542   int mask = 0, len;
543   const unsigned char c = (unsigned char)*p;
544
545   UTF8_COMPUTE(c, mask, len, -1);
546
547   (void)mask; /* quiet warning */
548
549   return len;
550 }
551
552 /* use when we want to skip errors */
553 int BLI_str_utf8_size_safe(const char *p)
554 {
555   int mask = 0, len;
556   const unsigned char c = (unsigned char)*p;
557
558   UTF8_COMPUTE(c, mask, len, 1);
559
560   (void)mask; /* quiet warning */
561
562   return len;
563 }
564
565 /* was g_utf8_get_char */
566 /**
567  * BLI_str_utf8_as_unicode:
568  * \param p: a pointer to Unicode character encoded as UTF-8
569  *
570  * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
571  * If \a p does not point to a valid UTF-8 encoded character, results are
572  * undefined. If you are not sure that the bytes are complete
573  * valid Unicode characters, you should use g_utf8_get_char_validated()
574  * instead.
575  *
576  * Return value: the resulting character
577  */
578 uint BLI_str_utf8_as_unicode(const char *p)
579 {
580   int i, len;
581   uint mask = 0;
582   uint result;
583   const unsigned char c = (unsigned char)*p;
584
585   UTF8_COMPUTE(c, mask, len, -1);
586   if (UNLIKELY(len == -1)) {
587     return BLI_UTF8_ERR;
588   }
589   UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR);
590
591   return result;
592 }
593
594 /* variant that increments the length */
595 uint BLI_str_utf8_as_unicode_and_size(const char *__restrict p, size_t *__restrict index)
596 {
597   int i, len;
598   unsigned mask = 0;
599   uint result;
600   const unsigned char c = (unsigned char)*p;
601
602   UTF8_COMPUTE(c, mask, len, -1);
603   if (UNLIKELY(len == -1)) {
604     return BLI_UTF8_ERR;
605   }
606   UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR);
607   *index += (size_t)len;
608   return result;
609 }
610
611 uint BLI_str_utf8_as_unicode_and_size_safe(const char *__restrict p, size_t *__restrict index)
612 {
613   int i, len;
614   uint mask = 0;
615   uint result;
616   const unsigned char c = (unsigned char)*p;
617
618   UTF8_COMPUTE(c, mask, len, -1);
619   if (UNLIKELY(len == -1)) {
620     *index += 1;
621     return c;
622   }
623   UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR);
624   *index += (size_t)len;
625   return result;
626 }
627
628 /* another variant that steps over the index,
629  * note, currently this also falls back to latin1 for text drawing. */
630 uint BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t *__restrict index)
631 {
632   int i, len;
633   uint mask = 0;
634   uint result;
635   unsigned char c;
636
637   p += *index;
638   c = (unsigned char)*p;
639
640   UTF8_COMPUTE(c, mask, len, -1);
641   if (UNLIKELY(len == -1)) {
642     /* when called with NULL end, result will never be NULL,
643      * checks for a NULL character */
644     const char *p_next = BLI_str_find_next_char_utf8(p, NULL);
645     /* will never return the same pointer unless '\0',
646      * eternal loop is prevented */
647     *index += (size_t)(p_next - p);
648     return BLI_UTF8_ERR;
649   }
650
651   /* this is tricky since there are a few ways we can bail out of bad unicode
652    * values, 3 possible solutions. */
653 #if 0
654   UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR);
655 #elif 1
656   /* WARNING: this is NOT part of glib, or supported by similar functions.
657    * this is added for text drawing because some filepaths can have latin1
658    * characters */
659   UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR);
660   if (result == BLI_UTF8_ERR) {
661     len = 1;
662     result = *p;
663   }
664   /* end warning! */
665 #else
666   /* without a fallback like '?', text drawing will stop on this value */
667   UTF8_GET(result, p, i, mask, len, '?');
668 #endif
669
670   *index += (size_t)len;
671   return result;
672 }
673
674 /* was g_unichar_to_utf8 */
675 /**
676  * BLI_str_utf8_from_unicode:
677  * \param c: a Unicode character code
678  * \param outbuf: output buffer, must have at least 6 bytes of space.
679  *       If %NULL, the length will be computed and returned
680  *       and nothing will be written to outbuf.
681  *
682  * Converts a single character to UTF-8.
683  *
684  * \return number of bytes written
685  */
686 size_t BLI_str_utf8_from_unicode(uint c, char *outbuf)
687 {
688   /* If this gets modified, also update the copy in g_string_insert_unichar() */
689   uint len = 0;
690   uint first;
691   uint i;
692
693   if (c < 0x80) {
694     first = 0;
695     len = 1;
696   }
697   else if (c < 0x800) {
698     first = 0xc0;
699     len = 2;
700   }
701   else if (c < 0x10000) {
702     first = 0xe0;
703     len = 3;
704   }
705   else if (c < 0x200000) {
706     first = 0xf0;
707     len = 4;
708   }
709   else if (c < 0x4000000) {
710     first = 0xf8;
711     len = 5;
712   }
713   else {
714     first = 0xfc;
715     len = 6;
716   }
717
718   if (outbuf) {
719     for (i = len - 1; i > 0; i--) {
720       outbuf[i] = (c & 0x3f) | 0x80;
721       c >>= 6;
722     }
723     outbuf[0] = c | first;
724   }
725
726   return len;
727 }
728
729 /* was g_utf8_find_prev_char */
730 /**
731  * BLI_str_find_prev_char_utf8:
732  * \param str: pointer to the beginning of a UTF-8 encoded string
733  * \param p: pointer to some position within \a str
734  *
735  * Given a position \a p with a UTF-8 encoded string \a str, find the start
736  * of the previous UTF-8 character starting before. \a p Returns %NULL if no
737  * UTF-8 characters are present in \a str before \a p
738  *
739  * \a p does not have to be at the beginning of a UTF-8 character. No check
740  * is made to see if the character found is actually valid other than
741  * it starts with an appropriate byte.
742  *
743  * Return value: a pointer to the found character or %NULL.
744  */
745 char *BLI_str_find_prev_char_utf8(const char *str, const char *p)
746 {
747   for (--p; p >= str; p--) {
748     if ((*p & 0xc0) != 0x80) {
749       return (char *)p;
750     }
751   }
752   return NULL;
753 }
754
755 /* was g_utf8_find_next_char */
756 /**
757  * BLI_str_find_next_char_utf8:
758  * \param p: a pointer to a position within a UTF-8 encoded string
759  * \param end: a pointer to the byte following the end of the string,
760  * or %NULL to indicate that the string is nul-terminated.
761  *
762  * Finds the start of the next UTF-8 character in the string after \a p
763  *
764  * \a p does not have to be at the beginning of a UTF-8 character. No check
765  * is made to see if the character found is actually valid other than
766  * it starts with an appropriate byte.
767  *
768  * Return value: a pointer to the found character or %NULL
769  */
770 char *BLI_str_find_next_char_utf8(const char *p, const char *end)
771 {
772   if (*p) {
773     if (end) {
774       for (++p; p < end && (*p & 0xc0) == 0x80; p++) {
775         /* do nothing */
776       }
777     }
778     else {
779       for (++p; (*p & 0xc0) == 0x80; p++) {
780         /* do nothing */
781       }
782     }
783   }
784   return (p == end) ? NULL : (char *)p;
785 }
786
787 /* was g_utf8_prev_char */
788 /**
789  * BLI_str_prev_char_utf8:
790  * \param p: a pointer to a position within a UTF-8 encoded string
791  *
792  * Finds the previous UTF-8 character in the string before \a p
793  *
794  * \a p does not have to be at the beginning of a UTF-8 character. No check
795  * is made to see if the character found is actually valid other than
796  * it starts with an appropriate byte. If \a p might be the first
797  * character of the string, you must use g_utf8_find_prev_char() instead.
798  *
799  * Return value: a pointer to the found character.
800  */
801 char *BLI_str_prev_char_utf8(const char *p)
802 {
803   while (1) {
804     p--;
805     if ((*p & 0xc0) != 0x80) {
806       return (char *)p;
807     }
808   }
809 }
810 /* end glib copy */
811
812 size_t BLI_str_partition_utf8(const char *str,
813                               const uint delim[],
814                               const char **sep,
815                               const char **suf)
816 {
817   return BLI_str_partition_ex_utf8(str, NULL, delim, sep, suf, false);
818 }
819
820 size_t BLI_str_rpartition_utf8(const char *str,
821                                const uint delim[],
822                                const char **sep,
823                                const char **suf)
824 {
825   return BLI_str_partition_ex_utf8(str, NULL, delim, sep, suf, true);
826 }
827
828 size_t BLI_str_partition_ex_utf8(const char *str,
829                                  const char *end,
830                                  const uint delim[],
831                                  const char **sep,
832                                  const char **suf,
833                                  const bool from_right)
834 {
835   const uint *d;
836   const size_t str_len = end ? (size_t)(end - str) : strlen(str);
837   size_t index;
838
839   /* Note that here, we assume end points to a valid utf8 char! */
840   BLI_assert(end == NULL || (end >= str && (BLI_str_utf8_as_unicode(end) != BLI_UTF8_ERR)));
841
842   *suf = (char *)(str + str_len);
843
844   for (*sep = (char *)(from_right ? BLI_str_find_prev_char_utf8(str, str + str_len) : str),
845       index = 0;
846        *sep >= str && (!end || *sep < end) && **sep != '\0';
847        *sep = (char *)(from_right ? BLI_str_find_prev_char_utf8(str, *sep) : str + index)) {
848     const uint c = BLI_str_utf8_as_unicode_and_size(*sep, &index);
849
850     if (c == BLI_UTF8_ERR) {
851       *suf = *sep = NULL;
852       break;
853     }
854
855     for (d = delim; *d != '\0'; d++) {
856       if (*d == c) {
857         /* *suf is already correct in case from_right is true. */
858         if (!from_right) {
859           *suf = (char *)(str + index);
860         }
861         return (size_t)(*sep - str);
862       }
863     }
864
865     *suf = *sep; /* Useful in 'from_right' case! */
866   }
867
868   *suf = *sep = NULL;
869   return str_len;
870 }
871
872 /* -------------------------------------------------------------------- */
873 /** \name Offset Conversion in Strings
874  * \{ */
875
876 int BLI_str_utf8_offset_to_index(const char *str, int offset)
877 {
878   int index = 0, pos = 0;
879   while (pos != offset) {
880     pos += BLI_str_utf8_size(str + pos);
881     index++;
882   }
883   return index;
884 }
885
886 int BLI_str_utf8_offset_from_index(const char *str, int index)
887 {
888   int offset = 0, pos = 0;
889   while (pos != index) {
890     offset += BLI_str_utf8_size(str + offset);
891     pos++;
892   }
893   return offset;
894 }
895
896 int BLI_str_utf8_offset_to_column(const char *str, int offset)
897 {
898   int column = 0, pos = 0;
899   while (pos < offset) {
900     column += BLI_str_utf8_char_width_safe(str + pos);
901     pos += BLI_str_utf8_size_safe(str + pos);
902   }
903   return column;
904 }
905
906 int BLI_str_utf8_offset_from_column(const char *str, int column)
907 {
908   int offset = 0, pos = 0, col;
909   while (*(str + offset) && pos < column) {
910     col = BLI_str_utf8_char_width_safe(str + offset);
911     if (pos + col > column) {
912       break;
913     }
914     offset += BLI_str_utf8_size_safe(str + offset);
915     pos += col;
916   }
917   return offset;
918 }
919
920 /** \} */