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