Coverage Report

Created: 2025-11-16 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/glib/gutf8.c
Line
Count
Source
1
/* gutf8.c - Operations on UTF-8 strings.
2
 *
3
 * Copyright (C) 1999 Tom Tromey
4
 * Copyright (C) 2000, 2015-2022 Red Hat, Inc.
5
 * Copyright (C) 2022-2023 David Rheinsberg
6
 *
7
 * SPDX-License-Identifier: LGPL-2.1-or-later
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "config.h"
24
25
#include <stdlib.h>
26
#ifdef HAVE_CODESET
27
#include <langinfo.h>
28
#endif
29
#include <string.h>
30
31
#ifdef G_PLATFORM_WIN32
32
#include <stdio.h>
33
#include <windows.h>
34
#endif
35
36
#include "gconvert.h"
37
#include "ghash.h"
38
#include "gstrfuncs.h"
39
#include "gtestutils.h"
40
#include "gtypes.h"
41
#include "gthread.h"
42
#include "glibintl.h"
43
#include "gvalgrind.h"
44
45
#define UTF8_COMPUTE(Char, Mask, Len)               \
46
0
  if (Char < 128)                   \
47
0
    {                       \
48
0
      Len = 1;                      \
49
0
      Mask = 0x7f;                    \
50
0
    }                        \
51
0
  else if ((Char & 0xe0) == 0xc0)               \
52
0
    {                       \
53
0
      Len = 2;                      \
54
0
      Mask = 0x1f;                    \
55
0
    }                        \
56
0
  else if ((Char & 0xf0) == 0xe0)               \
57
0
    {                       \
58
0
      Len = 3;                      \
59
0
      Mask = 0x0f;                    \
60
0
    }                        \
61
0
  else if ((Char & 0xf8) == 0xf0)               \
62
0
    {                       \
63
0
      Len = 4;                      \
64
0
      Mask = 0x07;                    \
65
0
    }                        \
66
0
  else if ((Char & 0xfc) == 0xf8)               \
67
0
    {                       \
68
0
      Len = 5;                      \
69
0
      Mask = 0x03;                    \
70
0
    }                        \
71
0
  else if ((Char & 0xfe) == 0xfc)               \
72
0
    {                       \
73
0
      Len = 6;                      \
74
0
      Mask = 0x01;                    \
75
0
    }                        \
76
0
  else                        \
77
0
    Len = -1;
78
79
#define UTF8_LENGTH(Char)              \
80
0
  ((Char) < 0x80 ? 1 :                 \
81
0
   ((Char) < 0x800 ? 2 :               \
82
0
    ((Char) < 0x10000 ? 3 :            \
83
0
     ((Char) < 0x200000 ? 4 :          \
84
0
      ((Char) < 0x4000000 ? 5 : 6)))))
85
   
86
87
#define UTF8_GET(Result, Chars, Count, Mask, Len)           \
88
0
  (Result) = (Chars)[0] & (Mask);               \
89
0
  for ((Count) = 1; (Count) < (Len); ++(Count))             \
90
0
    {                       \
91
0
      if (((Chars)[(Count)] & 0xc0) != 0x80)             \
92
0
  {                     \
93
0
    (Result) = -1;                  \
94
0
    break;                    \
95
0
  }                      \
96
0
      (Result) <<= 6;                   \
97
0
      (Result) |= ((Chars)[(Count)] & 0x3f);              \
98
0
    }
99
    
100
/*
101
 * Check whether a Unicode (5.2) char is in a valid range.
102
 *
103
 * The first check comes from the Unicode guarantee to never encode
104
 * a point above 0x0010ffff, since UTF-16 couldn't represent it.
105
 * 
106
 * The second check covers surrogate pairs (category Cs).
107
 *
108
 * @param Char the character
109
 */
110
#define UNICODE_VALID(Char)                   \
111
0
    ((Char) < 0x110000 &&                     \
112
0
     (((Char) & 0xFFFFF800) != 0xD800))
113
114
    
115
static const gchar utf8_skip_data[256] = {
116
  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,
117
  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,
118
  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,
119
  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,
120
  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,
121
  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,
122
  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,
123
  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
124
};
125
126
const gchar * const g_utf8_skip = utf8_skip_data;
127
128
/**
129
 * g_utf8_find_prev_char:
130
 * @str: pointer to the beginning of a UTF-8 encoded string
131
 * @p: pointer to some position within @str
132
 * 
133
 * Given a position @p with a UTF-8 encoded string @str, find the start
134
 * of the previous UTF-8 character starting before @p. Returns `NULL` if no
135
 * UTF-8 characters are present in @str before @p.
136
 *
137
 * @p does not have to be at the beginning of a UTF-8 character. No check
138
 * is made to see if the character found is actually valid other than
139
 * it starts with an appropriate byte.
140
 *
141
 * Returns: (transfer none) (nullable): a pointer to the found character
142
 */
143
gchar *
144
g_utf8_find_prev_char (const gchar *str,
145
           const gchar *p)
146
0
{
147
0
  while (p > str)
148
0
    {
149
0
      --p;
150
0
      if ((*p & 0xc0) != 0x80)
151
0
  return (gchar *)p;
152
0
    }
153
0
  return NULL;
154
0
}
155
156
/**
157
 * g_utf8_find_next_char:
158
 * @p: a pointer to a position within a UTF-8 encoded string
159
 * @end: (nullable): a pointer to the byte following the end of the string,
160
 *     or `NULL` to indicate that the string is nul-terminated
161
 *
162
 * Finds the start of the next UTF-8 character in the string after @p.
163
 *
164
 * @p does not have to be at the beginning of a UTF-8 character. No check
165
 * is made to see if the character found is actually valid other than
166
 * it starts with an appropriate byte.
167
 * 
168
 * If @end is `NULL`, the return value will never be `NULL`: if the end of the
169
 * string is reached, a pointer to the terminating nul byte is returned. If
170
 * @end is non-`NULL`, the return value will be `NULL` if the end of the string
171
 * is reached.
172
 *
173
 * Returns: (transfer none) (nullable): a pointer to the found character or `NULL` if @end is
174
 *    set and is reached
175
 */
176
gchar *
177
g_utf8_find_next_char (const gchar *p,
178
           const gchar *end)
179
0
{
180
0
  if (end)
181
0
    {
182
0
      for (++p; p < end && (*p & 0xc0) == 0x80; ++p)
183
0
        ;
184
0
      return (p >= end) ? NULL : (gchar *)p;
185
0
    }
186
0
  else
187
0
    {
188
0
      for (++p; (*p & 0xc0) == 0x80; ++p)
189
0
        ;
190
0
      return (gchar *)p;
191
0
    }
192
0
}
193
194
/**
195
 * g_utf8_prev_char:
196
 * @p: a pointer to a position within a UTF-8 encoded string
197
 *
198
 * Finds the previous UTF-8 character in the string before @p.
199
 *
200
 * @p does not have to be at the beginning of a UTF-8 character. No check
201
 * is made to see if the character found is actually valid other than
202
 * it starts with an appropriate byte. If @p might be the first
203
 * character of the string, you must use [func@GLib.utf8_find_prev_char]
204
 * instead.
205
 * 
206
 * Returns: (transfer none) (not nullable): a pointer to the found character
207
 */
208
gchar *
209
g_utf8_prev_char (const gchar *p)
210
0
{
211
0
  while (TRUE)
212
0
    {
213
0
      p--;
214
0
      if ((*p & 0xc0) != 0x80)
215
0
  return (gchar *)p;
216
0
    }
217
0
}
218
 
219
/**
220
 * g_utf8_strlen:
221
 * @p: pointer to the start of a UTF-8 encoded string
222
 * @max: the maximum number of bytes to examine. If @max
223
 *   is less than 0, then the string is assumed to be
224
 *   nul-terminated. If @max is 0, @p will not be examined and
225
 *   may be `NULL`. If @max is greater than 0, up to @max
226
 *   bytes are examined
227
 *
228
 * Computes the length of the string in characters, not including
229
 * the terminating nul character. If the @max’th byte falls in the
230
 * middle of a character, the last (partial) character is not counted.
231
 *
232
 * Returns: the length of the string in characters
233
 */
234
glong
235
g_utf8_strlen (const gchar *p,
236
               gssize       max)
237
0
{
238
0
  glong len = 0;
239
0
  const gchar *start = p;
240
0
  g_return_val_if_fail (p != NULL || max == 0, 0);
241
242
0
  if (max < 0)
243
0
    {
244
0
      while (*p)
245
0
        {
246
0
          p = g_utf8_next_char (p);
247
0
          ++len;
248
0
        }
249
0
    }
250
0
  else
251
0
    {
252
0
      if (max == 0 || !*p)
253
0
        return 0;
254
255
0
      p = g_utf8_next_char (p);
256
257
0
      while (p - start < max && *p)
258
0
        {
259
0
          ++len;
260
0
          p = g_utf8_next_char (p);
261
0
        }
262
263
      /* only do the last len increment if we got a complete
264
       * char (don't count partial chars)
265
       */
266
0
      if (p - start <= max)
267
0
        ++len;
268
0
    }
269
270
0
  return len;
271
0
}
272
273
/**
274
 * g_utf8_substring:
275
 * @str: a UTF-8 encoded string
276
 * @start_pos: a character offset within @str
277
 * @end_pos: another character offset within @str,
278
 *   or `-1` to indicate the end of the string
279
 *
280
 * Copies a substring out of a UTF-8 encoded string.
281
 * The substring will contain @end_pos - @start_pos characters.
282
 *
283
 * Since GLib 2.72, `-1` can be passed to @end_pos to indicate the
284
 * end of the string.
285
 *
286
 * Returns: (transfer full): a newly allocated copy of the requested
287
 *   substring. Free with [func@GLib.free] when no longer needed.
288
 *
289
 * Since: 2.30
290
 */
291
gchar *
292
g_utf8_substring (const gchar *str,
293
                  glong        start_pos,
294
                  glong        end_pos)
295
0
{
296
0
  gchar *start, *end, *out;
297
298
0
  g_return_val_if_fail (end_pos >= start_pos || end_pos == -1, NULL);
299
300
0
  start = g_utf8_offset_to_pointer (str, start_pos);
301
302
0
  if (end_pos == -1)
303
0
    {
304
0
      glong length = g_utf8_strlen (start, -1);
305
0
      end = g_utf8_offset_to_pointer (start, length);
306
0
    }
307
0
  else
308
0
    {
309
0
      end = g_utf8_offset_to_pointer (start, end_pos - start_pos);
310
0
    }
311
312
0
  out = g_malloc (end - start + 1);
313
0
  memcpy (out, start, end - start);
314
0
  out[end - start] = 0;
315
316
0
  return out;
317
0
}
318
319
/**
320
 * g_utf8_get_char:
321
 * @p: a pointer to Unicode character encoded as UTF-8
322
 * 
323
 * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
324
 *
325
 * If @p does not point to a valid UTF-8 encoded character, results
326
 * are undefined. If you are not sure that the bytes are complete
327
 * valid Unicode characters, you should use [func@GLib.utf8_get_char_validated]
328
 * instead.
329
 * 
330
 * Returns: the resulting character
331
 */
332
gunichar
333
g_utf8_get_char (const gchar *p)
334
0
{
335
0
  int i, mask = 0, len;
336
0
  gunichar result;
337
0
  unsigned char c = (unsigned char) *p;
338
339
0
  UTF8_COMPUTE (c, mask, len);
340
0
  if (len == -1)
341
0
    return (gunichar)-1;
342
0
  UTF8_GET (result, p, i, mask, len);
343
344
0
  return result;
345
0
}
346
347
/**
348
 * g_utf8_offset_to_pointer:
349
 * @str: a UTF-8 encoded string
350
 * @offset: a character offset within @str
351
 *
352
 * Converts from an integer character offset to a pointer to a position
353
 * within the string.
354
 *
355
 * Since 2.10, this function allows to pass a negative @offset to
356
 * step backwards. It is usually worth stepping backwards from the end
357
 * instead of forwards if @offset is in the last fourth of the string,
358
 * since moving forward is about 3 times faster than moving backward.
359
 *
360
 * Note that this function doesn’t abort when reaching the end of @str.
361
 * Therefore you should be sure that @offset is within string boundaries
362
 * before calling that function. Call [func@GLib.utf8_strlen] when unsure.
363
 * This limitation exists as this function is called frequently during
364
 * text rendering and therefore has to be as fast as possible.
365
 *
366
 * Returns: (transfer none): the resulting pointer
367
 */
368
gchar *
369
g_utf8_offset_to_pointer  (const gchar *str,
370
         glong        offset)
371
0
{
372
0
  const gchar *s = str;
373
374
0
  if (offset > 0) 
375
0
    while (offset--)
376
0
      s = g_utf8_next_char (s);
377
0
  else
378
0
    {
379
0
      const char *s1;
380
381
      /* This nice technique for fast backwards stepping 
382
       * through a UTF-8 string was dubbed "stutter stepping" 
383
       * by its inventor, Larry Ewing.
384
       */
385
0
      while (offset)
386
0
  {
387
0
    s1 = s;
388
0
    s += offset;
389
0
    while ((*s & 0xc0) == 0x80)
390
0
      s--;
391
392
0
    offset += g_utf8_pointer_to_offset (s, s1);
393
0
  }
394
0
    }
395
396
0
  return (gchar *)s;
397
0
}
398
399
/**
400
 * g_utf8_pointer_to_offset:
401
 * @str: a UTF-8 encoded string
402
 * @pos: a pointer to a position within @str
403
 * 
404
 * Converts from a pointer to position within a string to an integer
405
 * character offset.
406
 *
407
 * Since 2.10, this function allows @pos to be before @str, and returns
408
 * a negative offset in this case.
409
 * 
410
 * Returns: the resulting character offset
411
 */
412
glong    
413
g_utf8_pointer_to_offset (const gchar *str,
414
        const gchar *pos)
415
0
{
416
0
  const gchar *s = str;
417
0
  glong offset = 0;    
418
419
0
  if (pos < str) 
420
0
    offset = - g_utf8_pointer_to_offset (pos, str);
421
0
  else
422
0
    while (s < pos)
423
0
      {
424
0
  s = g_utf8_next_char (s);
425
0
  offset++;
426
0
      }
427
  
428
0
  return offset;
429
0
}
430
431
432
/**
433
 * g_utf8_strncpy:
434
 * @dest: (transfer none): buffer to fill with characters from @src
435
 * @src: UTF-8 encoded string
436
 * @n: character count
437
 * 
438
 * Like the standard C [`strncpy()`](man:strncpy) function, but copies a given
439
 * number of characters instead of a given number of bytes.
440
 *
441
 * The @src string must be valid UTF-8 encoded text. (Use
442
 * [func@GLib.utf8_validate] on all text before trying to use UTF-8 utility
443
 * functions with it.)
444
 * 
445
 * Note you must ensure @dest is at least 4 * @n + 1 to fit the
446
 * largest possible UTF-8 characters
447
 *
448
 * Returns: (transfer none): @dest
449
 */
450
gchar *
451
g_utf8_strncpy (gchar       *dest,
452
    const gchar *src,
453
    gsize        n)
454
0
{
455
0
  const gchar *s = src;
456
0
  while (n && *s)
457
0
    {
458
0
      s = g_utf8_next_char(s);
459
0
      n--;
460
0
    }
461
0
  strncpy(dest, src, s - src);
462
0
  dest[s - src] = 0;
463
0
  return dest;
464
0
}
465
466
/**
467
 * g_utf8_truncate_middle:
468
 * @string: (transfer none): a nul-terminated UTF-8 encoded string
469
 * @truncate_length: the new size of @string, in characters, including the ellipsis character
470
 *
471
 * Cuts off the middle of the string, preserving half of @truncate_length
472
 * characters at the beginning and half at the end.
473
 * 
474
 * If @string is already short enough, this returns a copy of @string.
475
 * If @truncate_length is `0`, an empty string is returned.
476
 *
477
 * Returns: (transfer full): a newly-allocated copy of @string ellipsized in the middle
478
 *
479
 * Since: 2.78
480
 */
481
gchar *
482
g_utf8_truncate_middle (const gchar *string,
483
                        gsize        truncate_length)
484
0
{
485
0
  const gchar *ellipsis = "…";
486
0
  const gsize ellipsis_bytes = strlen (ellipsis);
487
488
0
  gsize length;
489
0
  gsize left_substring_length;
490
0
  gchar *left_substring_end;
491
0
  gchar *right_substring_begin;
492
0
  gchar *right_substring_end;
493
0
  gsize left_bytes;
494
0
  gsize right_bytes;
495
0
  gchar *result;
496
497
0
  g_return_val_if_fail (string != NULL, NULL);
498
499
0
  length = g_utf8_strlen (string, -1);
500
  /* Current string already smaller than requested length */
501
0
  if (length <= truncate_length)
502
0
    return g_strdup (string);
503
0
  if (truncate_length == 0)
504
0
    return g_strdup ("");
505
506
  /* Find substrings to keep, ignore ellipsis character for that */
507
0
  truncate_length -= 1;
508
509
0
  left_substring_length = truncate_length / 2;
510
511
0
  left_substring_end = g_utf8_offset_to_pointer (string, left_substring_length);
512
0
  right_substring_begin = g_utf8_offset_to_pointer (left_substring_end,
513
0
                                                    length - truncate_length);
514
0
  right_substring_end = g_utf8_offset_to_pointer (right_substring_begin,
515
0
                                                  truncate_length - left_substring_length);
516
517
0
  g_assert (*right_substring_end == '\0');
518
519
0
  left_bytes = left_substring_end - string;
520
0
  right_bytes = right_substring_end - right_substring_begin;
521
522
0
  result = g_malloc (left_bytes + ellipsis_bytes + right_bytes + 1);
523
524
0
  strncpy (result, string, left_bytes);
525
0
  memcpy (result + left_bytes, ellipsis, ellipsis_bytes);
526
0
  strncpy (result + left_bytes + ellipsis_bytes, right_substring_begin, right_bytes);
527
0
  result[left_bytes + ellipsis_bytes + right_bytes] = '\0';
528
529
0
  return result;
530
0
}
531
532
/* unicode_strchr */
533
534
/**
535
 * g_unichar_to_utf8:
536
 * @c: a Unicode character code
537
 * @outbuf: (out caller-allocates) (optional): output buffer, must have at
538
 *   least 6 bytes of space. If `NULL`, the length will be computed and
539
 *   returned and nothing will be written to @outbuf.
540
 * 
541
 * Converts a single character to UTF-8.
542
 * 
543
 * Returns: number of bytes written
544
 */
545
int
546
g_unichar_to_utf8 (gunichar c,
547
       gchar   *outbuf)
548
0
{
549
  /* If this gets modified, also update the copy in g_string_insert_unichar() */
550
0
  guint len = 0;    
551
0
  int first;
552
0
  int i;
553
554
0
  if (c < 0x80)
555
0
    {
556
0
      first = 0;
557
0
      len = 1;
558
0
    }
559
0
  else if (c < 0x800)
560
0
    {
561
0
      first = 0xc0;
562
0
      len = 2;
563
0
    }
564
0
  else if (c < 0x10000)
565
0
    {
566
0
      first = 0xe0;
567
0
      len = 3;
568
0
    }
569
0
   else if (c < 0x200000)
570
0
    {
571
0
      first = 0xf0;
572
0
      len = 4;
573
0
    }
574
0
  else if (c < 0x4000000)
575
0
    {
576
0
      first = 0xf8;
577
0
      len = 5;
578
0
    }
579
0
  else
580
0
    {
581
0
      first = 0xfc;
582
0
      len = 6;
583
0
    }
584
585
0
  if (outbuf)
586
0
    {
587
0
      for (i = len - 1; i > 0; --i)
588
0
  {
589
0
    outbuf[i] = (c & 0x3f) | 0x80;
590
0
    c >>= 6;
591
0
  }
592
0
      outbuf[0] = c | first;
593
0
    }
594
595
0
  return len;
596
0
}
597
598
/**
599
 * g_utf8_strchr:
600
 * @p: a nul-terminated UTF-8 encoded string
601
 * @len: the maximum length of @p
602
 * @c: a Unicode character
603
 * 
604
 * Finds the leftmost occurrence of the given Unicode character
605
 * in a UTF-8 encoded string, while limiting the search to @len bytes.
606
 * 
607
 * If @len is `-1`, allow unbounded search.
608
 *
609
 * Returns: (transfer none) (nullable): `NULL` if the string does not contain
610
 *   the character, otherwise, a pointer to the start of the leftmost occurrence
611
 *   of the character in the string.
612
 */
613
gchar *
614
g_utf8_strchr (const char *p,
615
         gssize      len,
616
         gunichar    c)
617
0
{
618
0
  gchar ch[10];
619
620
0
  gint charlen = g_unichar_to_utf8 (c, ch);
621
0
  ch[charlen] = '\0';
622
  
623
0
  return g_strstr_len (p, len, ch);
624
0
}
625
626
627
/**
628
 * g_utf8_strrchr:
629
 * @p: a nul-terminated UTF-8 encoded string
630
 * @len: the maximum length of @p
631
 * @c: a Unicode character
632
 * 
633
 * Find the rightmost occurrence of the given Unicode character
634
 * in a UTF-8 encoded string, while limiting the search to @len bytes.
635
 * 
636
 * If @len is `-1`, allow unbounded search.
637
 *
638
 * Returns: (transfer none) (nullable): `NULL` if the string does not contain
639
 *   the character, otherwise, a pointer to the start of the rightmost
640
 *   occurrence of the character in the string.
641
 */
642
gchar *
643
g_utf8_strrchr (const char *p,
644
    gssize      len,
645
    gunichar    c)
646
0
{
647
0
  gchar ch[10];
648
649
0
  gint charlen = g_unichar_to_utf8 (c, ch);
650
0
  ch[charlen] = '\0';
651
  
652
0
  return g_strrstr_len (p, len, ch);
653
0
}
654
655
656
/* Like g_utf8_get_char, but take a maximum length
657
 * and return (gunichar)-2 on incomplete trailing character;
658
 * also check for malformed or overlong sequences
659
 * and return (gunichar)-1 in this case.
660
 */
661
static inline gunichar
662
g_utf8_get_char_extended (const  gchar *p,
663
        gssize max_len)
664
0
{
665
0
  gsize i, len;
666
0
  gunichar min_code;
667
0
  gunichar wc = (guchar) *p;
668
0
  const gunichar partial_sequence = (gunichar) -2;
669
0
  const gunichar malformed_sequence = (gunichar) -1;
670
671
0
  if (wc < 0x80)
672
0
    {
673
0
      return wc;
674
0
    }
675
0
  else if (G_UNLIKELY (wc < 0xc0))
676
0
    {
677
0
      return malformed_sequence;
678
0
    }
679
0
  else if (wc < 0xe0)
680
0
    {
681
0
      len = 2;
682
0
      wc &= 0x1f;
683
0
      min_code = 1 << 7;
684
0
    }
685
0
  else if (wc < 0xf0)
686
0
    {
687
0
      len = 3;
688
0
      wc &= 0x0f;
689
0
      min_code = 1 << 11;
690
0
    }
691
0
  else if (wc < 0xf8)
692
0
    {
693
0
      len = 4;
694
0
      wc &= 0x07;
695
0
      min_code = 1 << 16;
696
0
    }
697
0
  else if (wc < 0xfc)
698
0
    {
699
0
      len = 5;
700
0
      wc &= 0x03;
701
0
      min_code = 1 << 21;
702
0
    }
703
0
  else if (wc < 0xfe)
704
0
    {
705
0
      len = 6;
706
0
      wc &= 0x01;
707
0
      min_code = 1 << 26;
708
0
    }
709
0
  else
710
0
    {
711
0
      return malformed_sequence;
712
0
    }
713
714
0
  if (G_UNLIKELY (max_len >= 0 && len > (gsize) max_len))
715
0
    {
716
0
      for (i = 1; i < (gsize) max_len; i++)
717
0
  {
718
0
    if ((((guchar *)p)[i] & 0xc0) != 0x80)
719
0
      return malformed_sequence;
720
0
  }
721
0
      return partial_sequence;
722
0
    }
723
724
0
  for (i = 1; i < len; ++i)
725
0
    {
726
0
      gunichar ch = ((guchar *)p)[i];
727
728
0
      if (G_UNLIKELY ((ch & 0xc0) != 0x80))
729
0
  {
730
0
    if (ch)
731
0
      return malformed_sequence;
732
0
    else
733
0
      return partial_sequence;
734
0
  }
735
736
0
      wc <<= 6;
737
0
      wc |= (ch & 0x3f);
738
0
    }
739
740
0
  if (G_UNLIKELY (wc < min_code))
741
0
    return malformed_sequence;
742
743
0
  return wc;
744
0
}
745
746
/**
747
 * g_utf8_get_char_validated:
748
 * @p: a pointer to Unicode character encoded as UTF-8
749
 * @max_len: the maximum number of bytes to read, or `-1` if @p is nul-terminated
750
 *
751
 * Convert a sequence of bytes encoded as UTF-8 to a Unicode character.
752
 *
753
 * This function checks for incomplete characters, for invalid characters
754
 * such as characters that are out of the range of Unicode, and for
755
 * overlong encodings of valid characters.
756
 *
757
 * Note that [func@GLib.utf8_get_char_validated] returns `(gunichar)-2` if
758
 * @max_len is positive and any of the bytes in the first UTF-8 character
759
 * sequence are nul.
760
 * 
761
 * Returns: the resulting character. If @p points to a partial
762
 *   sequence at the end of a string that could begin a valid
763
 *   character (or if @max_len is zero), returns `(gunichar)-2`;
764
 *   otherwise, if @p does not point to a valid UTF-8 encoded
765
 *   Unicode character, returns `(gunichar)-1`.
766
 */
767
gunichar
768
g_utf8_get_char_validated (const gchar *p,
769
         gssize       max_len)
770
0
{
771
0
  gunichar result;
772
773
0
  if (max_len == 0)
774
0
    return (gunichar)-2;
775
776
0
  result = g_utf8_get_char_extended (p, max_len);
777
778
  /* Disallow codepoint U+0000 as it’s a nul byte,
779
   * and all string handling in GLib is nul-terminated */
780
0
  if (result == 0 && max_len > 0)
781
0
    return (gunichar) -2;
782
783
0
  if (result & 0x80000000)
784
0
    return result;
785
0
  else if (!UNICODE_VALID (result))
786
0
    return (gunichar)-1;
787
0
  else
788
0
    return result;
789
0
}
790
791
0
#define CONT_BYTE_FAST(p) ((guchar)*p++ & 0x3f)
792
793
/**
794
 * g_utf8_to_ucs4_fast:
795
 * @str: a UTF-8 encoded string
796
 * @len: the maximum length of @str to use, in bytes. If @len is negative,
797
 *   then the string is nul-terminated.
798
 * @items_written: (out) (optional): location to store the
799
 *   number of characters in the result, or `NULL`.
800
 *
801
 * Convert a string from UTF-8 to a 32-bit fixed width
802
 * representation as UCS-4, assuming valid UTF-8 input.
803
 *
804
 * This function is roughly twice as fast as [func@GLib.utf8_to_ucs4]
805
 * but does no error checking on the input. A trailing nul character (U+0000)
806
 * will be added to the string after the converted text.
807
 * 
808
 * Returns: (transfer full): a pointer to a newly allocated UCS-4 string.
809
 *   This value must be freed with [func@GLib.free].
810
 */
811
gunichar *
812
g_utf8_to_ucs4_fast (const gchar *str,
813
         glong        len,              
814
         glong       *items_written)    
815
0
{
816
0
  gunichar *result;
817
0
  gint n_chars, i;
818
0
  const gchar *p;
819
820
0
  g_return_val_if_fail (str != NULL, NULL);
821
822
0
  p = str;
823
0
  n_chars = 0;
824
0
  if (len < 0)
825
0
    {
826
0
      while (*p)
827
0
  {
828
0
    p = g_utf8_next_char (p);
829
0
    ++n_chars;
830
0
  }
831
0
    }
832
0
  else
833
0
    {
834
0
      while (p < str + len && *p)
835
0
  {
836
0
    p = g_utf8_next_char (p);
837
0
    ++n_chars;
838
0
  }
839
0
    }
840
  
841
0
  result = g_new (gunichar, n_chars + 1);
842
  
843
0
  p = str;
844
0
  for (i=0; i < n_chars; i++)
845
0
    {
846
0
      guchar first = (guchar)*p++;
847
0
      gunichar wc;
848
849
0
      if (first < 0xc0)
850
0
  {
851
          /* We really hope first < 0x80, but we don't want to test an
852
           * extra branch for invalid input, which this function
853
           * does not care about. Handling unexpected continuation bytes
854
           * here will do the least damage. */
855
0
    wc = first;
856
0
  }
857
0
      else
858
0
  {
859
0
          gunichar c1 = CONT_BYTE_FAST(p);
860
0
          if (first < 0xe0)
861
0
            {
862
0
              wc = ((first & 0x1f) << 6) | c1;
863
0
            }
864
0
          else
865
0
            {
866
0
              gunichar c2 = CONT_BYTE_FAST(p);
867
0
              if (first < 0xf0)
868
0
                {
869
0
                  wc = ((first & 0x0f) << 12) | (c1 << 6) | c2;
870
0
                }
871
0
              else
872
0
                {
873
0
                  gunichar c3 = CONT_BYTE_FAST(p);
874
0
                  wc = ((first & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3;
875
0
                  if (G_UNLIKELY (first >= 0xf8))
876
0
                    {
877
                      /* This can't be valid UTF-8, but g_utf8_next_char()
878
                       * and company allow out-of-range sequences */
879
0
                      gunichar mask = 1 << 20;
880
0
                      while ((wc & mask) != 0)
881
0
                        {
882
0
                          wc <<= 6;
883
0
                          wc |= CONT_BYTE_FAST(p);
884
0
                          mask <<= 5;
885
0
                        }
886
0
                      wc &= mask - 1;
887
0
                    }
888
0
                }
889
0
            }
890
0
  }
891
0
      result[i] = wc;
892
0
    }
893
0
  result[i] = 0;
894
895
0
  if (items_written)
896
0
    *items_written = i;
897
898
0
  return result;
899
0
}
900
901
static gpointer
902
try_malloc_n (gsize n_blocks, gsize n_block_bytes, GError **error)
903
0
{
904
0
    gpointer ptr = g_try_malloc_n (n_blocks, n_block_bytes);
905
0
    if (ptr == NULL)
906
0
      g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_MEMORY,
907
0
                           _("Failed to allocate memory"));
908
0
    return ptr;
909
0
}
910
911
/**
912
 * g_utf8_to_ucs4:
913
 * @str: a UTF-8 encoded string
914
 * @len: the maximum length of @str to use, in bytes. If @len is negative,
915
 *   then the string is nul-terminated.
916
 * @items_read: (out) (optional): location to store number of
917
  *  bytes read, or `NULL`.
918
 *   If `NULL`, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
919
 *   returned in case @str contains a trailing partial
920
 *   character. If an error occurs then the index of the
921
 *   invalid input is stored here.
922
 * @items_written: (out) (optional): location to store number
923
 *   of characters written or `NULL`. The value here stored does not include
924
 *   the trailing nul character.
925
 * @error: location to store the error occurring, or `NULL` to ignore
926
 *   errors. Any of the errors in [error@GLib.ConvertError] other than
927
 *   [error@GLib.ConvertError.NO_CONVERSION] may occur.
928
 *
929
 * Convert a string from UTF-8 to a 32-bit fixed width representation as UCS-4.
930
 *
931
 * A trailing nul character (U+0000) will be added to the string after the
932
 * converted text.
933
 * 
934
 * Returns: (transfer full): a pointer to a newly allocated UCS-4 string.
935
 *   This value must be freed with [func@GLib.free].
936
 */
937
gunichar *
938
g_utf8_to_ucs4 (const gchar *str,
939
    glong        len,             
940
    glong       *items_read,      
941
    glong       *items_written,   
942
    GError     **error)
943
0
{
944
0
  gunichar *result = NULL;
945
0
  gint n_chars, i;
946
0
  const gchar *in;
947
  
948
0
  in = str;
949
0
  n_chars = 0;
950
0
  while ((len < 0 || str + len - in > 0) && *in)
951
0
    {
952
0
      gunichar wc = g_utf8_get_char_extended (in, len < 0 ? 6 : str + len - in);
953
0
      if (wc & 0x80000000)
954
0
  {
955
0
    if (wc == (gunichar)-2)
956
0
      {
957
0
        if (items_read)
958
0
    break;
959
0
        else
960
0
    g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
961
0
                                     _("Partial character sequence at end of input"));
962
0
      }
963
0
    else
964
0
      g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
965
0
                                 _("Invalid byte sequence in conversion input"));
966
967
0
    goto err_out;
968
0
  }
969
970
0
      n_chars++;
971
972
0
      in = g_utf8_next_char (in);
973
0
    }
974
975
0
  result = try_malloc_n (n_chars + 1, sizeof (gunichar), error);
976
0
  if (result == NULL)
977
0
      goto err_out;
978
979
0
  in = str;
980
0
  for (i=0; i < n_chars; i++)
981
0
    {
982
0
      result[i] = g_utf8_get_char (in);
983
0
      in = g_utf8_next_char (in);
984
0
    }
985
0
  result[i] = 0;
986
987
0
  if (items_written)
988
0
    *items_written = n_chars;
989
990
0
 err_out:
991
0
  if (items_read)
992
0
    *items_read = in - str;
993
994
0
  return result;
995
0
}
996
997
/**
998
 * g_ucs4_to_utf8:
999
 * @str: (array length=len) (element-type gunichar): a UCS-4 encoded string
1000
 * @len: the maximum length (number of characters) of @str to use. 
1001
 *   If @len is negative, then the string is nul-terminated.
1002
 * @items_read: (out) (optional): location to store number of
1003
 *   characters read, or `NULL`.
1004
 * @items_written: (out) (optional): location to store number
1005
 *   of bytes written or `NULL`. The value here stored does not include the
1006
 *   trailing nul byte.
1007
 * @error: location to store the error occurring, or %NULL to ignore
1008
 *   errors. Any of the errors in #GConvertError other than
1009
 *   %G_CONVERT_ERROR_NO_CONVERSION may occur.
1010
 *
1011
 * Convert a string from a 32-bit fixed width representation as UCS-4.
1012
 * to UTF-8.
1013
 *
1014
 * The result will be terminated with a nul byte.
1015
 * 
1016
 * Returns: (transfer full): a pointer to a newly allocated UTF-8 string.
1017
 *   This value must be freed with [func@GLib.free]. If an error occurs,
1018
 *   @items_read will be set to the position of the first invalid input
1019
 *   character.
1020
 */
1021
gchar *
1022
g_ucs4_to_utf8 (const gunichar *str,
1023
    glong           len,              
1024
    glong          *items_read,       
1025
    glong          *items_written,    
1026
    GError        **error)
1027
0
{
1028
0
  gint result_length;
1029
0
  gchar *result = NULL;
1030
0
  gchar *p;
1031
0
  gint i;
1032
1033
0
  result_length = 0;
1034
0
  for (i = 0; len < 0 || i < len ; i++)
1035
0
    {
1036
0
      if (!str[i])
1037
0
  break;
1038
1039
0
      if (str[i] >= 0x80000000)
1040
0
  {
1041
0
    g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1042
0
                               _("Character out of range for UTF-8"));
1043
0
    goto err_out;
1044
0
  }
1045
      
1046
0
      result_length += UTF8_LENGTH (str[i]);
1047
0
    }
1048
1049
0
  result = try_malloc_n (result_length + 1, 1, error);
1050
0
  if (result == NULL)
1051
0
      goto err_out;
1052
1053
0
  p = result;
1054
1055
0
  i = 0;
1056
0
  while (p < result + result_length)
1057
0
    p += g_unichar_to_utf8 (str[i++], p);
1058
  
1059
0
  *p = '\0';
1060
1061
0
  if (items_written)
1062
0
    *items_written = p - result;
1063
1064
0
 err_out:
1065
0
  if (items_read)
1066
0
    *items_read = i;
1067
1068
0
  return result;
1069
0
}
1070
1071
0
#define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)
1072
1073
/**
1074
 * g_utf16_to_utf8:
1075
 * @str: (array length=len) (element-type guint16): a UTF-16 encoded string
1076
 * @len: the maximum length (number of #gunichar2) of @str to use. 
1077
 *   If @len is negative, then the string is nul-terminated.
1078
 * @items_read: (out) (optional): location to store number of words read, or
1079
 *   `NULL`. If `NULL`, then [error@GLib.ConvertError.PARTIAL_INPUT] will
1080
 *   be returned in case @str contains a trailing partial character. If
1081
 *   an error occurs then the index of the invalid input is stored here.
1082
 *   It’s guaranteed to be non-negative.
1083
 * @items_written: (out) (optional): location to store number
1084
 *   of bytes written, or `NULL`. The value stored here does not include the
1085
 *   trailing nul byte. It’s guaranteed to be non-negative.
1086
 * @error: location to store the error occurring, or `NULL` to ignore
1087
 *   errors. Any of the errors in [error@GLib.ConvertError] other than
1088
 *   [error@GLib.ConvertError.NO_CONVERSION] may occur.
1089
 *
1090
 * Convert a string from UTF-16 to UTF-8.
1091
 *
1092
 * The result will be terminated with a nul byte.
1093
 *
1094
 * Note that the input is expected to be already in native endianness,
1095
 * an initial byte-order-mark character is not handled specially.
1096
 * [func@GLib.convert] can be used to convert a byte buffer of UTF-16 data of
1097
 * ambiguous endianness.
1098
 *
1099
 * Further note that this function does not validate the result
1100
 * string; it may (for example) include embedded nul characters. The only
1101
 * validation done by this function is to ensure that the input can
1102
 * be correctly interpreted as UTF-16, i.e. it doesn’t contain
1103
 * unpaired surrogates or partial character sequences.
1104
 *
1105
 * Returns: (transfer full): a pointer to a newly allocated UTF-8 string.
1106
 *   This value must be freed with [func@GLib.free].
1107
 **/
1108
gchar *
1109
g_utf16_to_utf8 (const gunichar2  *str,
1110
     glong             len,
1111
     glong            *items_read,
1112
     glong            *items_written,
1113
     GError          **error)
1114
0
{
1115
  /* This function and g_utf16_to_ucs4 are almost exactly identical -
1116
   * The lines that differ are marked.
1117
   */
1118
0
  const gunichar2 *in;
1119
0
  gchar *out;
1120
0
  gchar *result = NULL;
1121
0
  gint n_bytes;
1122
0
  gunichar high_surrogate;
1123
1124
0
  g_return_val_if_fail (str != NULL, NULL);
1125
1126
0
  n_bytes = 0;
1127
0
  in = str;
1128
0
  high_surrogate = 0;
1129
0
  while ((len < 0 || in - str < len) && *in)
1130
0
    {
1131
0
      gunichar2 c = *in;
1132
0
      gunichar wc;
1133
1134
0
      if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1135
0
  {
1136
0
    if (high_surrogate)
1137
0
      {
1138
0
        wc = SURROGATE_VALUE (high_surrogate, c);
1139
0
        high_surrogate = 0;
1140
0
      }
1141
0
    else
1142
0
      {
1143
0
        g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1144
0
                                   _("Invalid sequence in conversion input"));
1145
0
        goto err_out;
1146
0
      }
1147
0
  }
1148
0
      else
1149
0
  {
1150
0
    if (high_surrogate)
1151
0
      {
1152
0
        g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1153
0
                                   _("Invalid sequence in conversion input"));
1154
0
        goto err_out;
1155
0
      }
1156
1157
0
    if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1158
0
      {
1159
0
        high_surrogate = c;
1160
0
        goto next1;
1161
0
      }
1162
0
    else
1163
0
      wc = c;
1164
0
  }
1165
1166
      /********** DIFFERENT for UTF8/UCS4 **********/
1167
0
      n_bytes += UTF8_LENGTH (wc);
1168
1169
0
    next1:
1170
0
      in++;
1171
0
    }
1172
1173
0
  if (high_surrogate && !items_read)
1174
0
    {
1175
0
      g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1176
0
                           _("Partial character sequence at end of input"));
1177
0
      goto err_out;
1178
0
    }
1179
  
1180
  /* At this point, everything is valid, and we just need to convert
1181
   */
1182
  /********** DIFFERENT for UTF8/UCS4 **********/
1183
0
  result = try_malloc_n (n_bytes + 1, 1, error);
1184
0
  if (result == NULL)
1185
0
      goto err_out;
1186
1187
0
  high_surrogate = 0;
1188
0
  out = result;
1189
0
  in = str;
1190
0
  while (out < result + n_bytes)
1191
0
    {
1192
0
      gunichar2 c = *in;
1193
0
      gunichar wc;
1194
1195
0
      if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1196
0
  {
1197
0
    wc = SURROGATE_VALUE (high_surrogate, c);
1198
0
    high_surrogate = 0;
1199
0
  }
1200
0
      else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1201
0
  {
1202
0
    high_surrogate = c;
1203
0
    goto next2;
1204
0
  }
1205
0
      else
1206
0
  wc = c;
1207
1208
      /********** DIFFERENT for UTF8/UCS4 **********/
1209
0
      out += g_unichar_to_utf8 (wc, out);
1210
1211
0
    next2:
1212
0
      in++;
1213
0
    }
1214
  
1215
  /********** DIFFERENT for UTF8/UCS4 **********/
1216
0
  *out = '\0';
1217
1218
0
  if (items_written)
1219
    /********** DIFFERENT for UTF8/UCS4 **********/
1220
0
    *items_written = out - result;
1221
1222
0
 err_out:
1223
0
  if (items_read)
1224
0
    *items_read = in - str;
1225
1226
0
  return result;
1227
0
}
1228
1229
/**
1230
 * g_utf16_to_ucs4:
1231
 * @str: (array length=len) (element-type guint16): a UTF-16 encoded string
1232
 * @len: the maximum length (number of #gunichar2) of @str to use. 
1233
 *   If @len is negative, then the string is nul-terminated.
1234
 * @items_read: (out) (optional): location to store number of words read, or
1235
 *   `NULL`. If `NULL`, then [error@GLib.ConvertError.PARTIAL_INPUT] will be
1236
 *   returned in case @str contains a trailing partial character. If
1237
 *   an error occurs then the index of the invalid input is stored here.
1238
 * @items_written: (out) (optional): location to store number
1239
 *   of characters written, or `NULL`. The value stored here does not include
1240
 *   the trailing nul character.
1241
 * @error: location to store the error occurring, or `NULL` to ignore
1242
 *   errors. Any of the errors in [error@GLib.ConvertError] other than
1243
 *   [error@GLib.ConvertError.NO_CONVERSION] may occur.
1244
 *
1245
 * Convert a string from UTF-16 to UCS-4.
1246
 *
1247
 * The result will be nul-terminated.
1248
 * 
1249
 * Returns: (transfer full): a pointer to a newly allocated UCS-4 string.
1250
 *   This value must be freed with [func@GLib.free].
1251
 */
1252
gunichar *
1253
g_utf16_to_ucs4 (const gunichar2  *str,
1254
     glong             len,              
1255
     glong            *items_read,       
1256
     glong            *items_written,    
1257
     GError          **error)
1258
0
{
1259
0
  const gunichar2 *in;
1260
0
  gchar *out;
1261
0
  gchar *result = NULL;
1262
0
  size_t n_bytes;
1263
0
  gunichar high_surrogate;
1264
1265
0
  g_return_val_if_fail (str != NULL, NULL);
1266
1267
0
  n_bytes = 0;
1268
0
  in = str;
1269
0
  high_surrogate = 0;
1270
0
  while ((len < 0 || in - str < len) && *in)
1271
0
    {
1272
0
      gunichar2 c = *in;
1273
1274
0
      if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1275
0
  {
1276
0
    if (high_surrogate)
1277
0
      {
1278
0
        high_surrogate = 0;
1279
0
      }
1280
0
    else
1281
0
      {
1282
0
        g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1283
0
                                   _("Invalid sequence in conversion input"));
1284
0
        goto err_out;
1285
0
      }
1286
0
  }
1287
0
      else
1288
0
  {
1289
0
    if (high_surrogate)
1290
0
      {
1291
0
        g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1292
0
                                   _("Invalid sequence in conversion input"));
1293
0
        goto err_out;
1294
0
      }
1295
1296
0
    if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1297
0
      {
1298
0
        high_surrogate = c;
1299
0
        goto next1;
1300
0
      }
1301
0
  }
1302
1303
      /********** DIFFERENT for UTF8/UCS4 **********/
1304
0
      n_bytes += sizeof (gunichar);
1305
1306
0
    next1:
1307
0
      in++;
1308
0
    }
1309
1310
0
  if (high_surrogate && !items_read)
1311
0
    {
1312
0
      g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1313
0
                           _("Partial character sequence at end of input"));
1314
0
      goto err_out;
1315
0
    }
1316
  
1317
  /* At this point, everything is valid, and we just need to convert
1318
   */
1319
  /********** DIFFERENT for UTF8/UCS4 **********/
1320
0
  result = try_malloc_n (n_bytes + 4, 1, error);
1321
0
  if (result == NULL)
1322
0
      goto err_out;
1323
1324
0
  high_surrogate = 0;
1325
0
  out = result;
1326
0
  in = str;
1327
0
  while (out < result + n_bytes)
1328
0
    {
1329
0
      gunichar2 c = *in;
1330
0
      gunichar wc;
1331
1332
0
      if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
1333
0
  {
1334
0
    wc = SURROGATE_VALUE (high_surrogate, c);
1335
0
    high_surrogate = 0;
1336
0
  }
1337
0
      else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
1338
0
  {
1339
0
    high_surrogate = c;
1340
0
    goto next2;
1341
0
  }
1342
0
      else
1343
0
  wc = c;
1344
1345
      /********** DIFFERENT for UTF8/UCS4 **********/
1346
0
      *(gunichar *)out = wc;
1347
0
      out += sizeof (gunichar);
1348
1349
0
    next2:
1350
0
      in++;
1351
0
    }
1352
1353
  /********** DIFFERENT for UTF8/UCS4 **********/
1354
0
  *(gunichar *)out = 0;
1355
1356
0
  if (items_written)
1357
    /********** DIFFERENT for UTF8/UCS4 **********/
1358
0
    *items_written = (out - result) / sizeof (gunichar);
1359
1360
0
 err_out:
1361
0
  if (items_read)
1362
0
    *items_read = in - str;
1363
1364
0
  return (gunichar *)result;
1365
0
}
1366
1367
/**
1368
 * g_utf8_to_utf16:
1369
 * @str: a UTF-8 encoded string
1370
 * @len: the maximum length (number of bytes) of @str to use.
1371
 *   If @len is negative, then the string is nul-terminated.
1372
 * @items_read: (out) (optional): location to store number of bytes read, or
1373
 *   `NULL`. If `NULL`, then [error@GLib.ConvertError.PARTIAL_INPUT] will
1374
 *   be returned in case @str contains a trailing partial character. If
1375
 *   an error occurs then the index of the invalid input is stored here.
1376
 * @items_written: (out) (optional): location to store number
1377
 *   of `gunichar2` written, or `NULL`. The value stored here does not include
1378
 *   the trailing nul.
1379
 * @error: location to store the error occurring, or `NULL` to ignore
1380
 *   errors. Any of the errors in [error@GLib.ConvertError] other than
1381
 *   [error@GLib.ConvertError.NO_CONVERSION] may occur.
1382
 *
1383
 * Convert a string from UTF-8 to UTF-16.
1384
 *
1385
 * A nul character (U+0000) will be added to the result after the converted text.
1386
 *
1387
 * Returns: (transfer full): a pointer to a newly allocated UTF-16 string.
1388
 *   This value must be freed with [func@GLib.free].
1389
 */
1390
gunichar2 *
1391
g_utf8_to_utf16 (const gchar *str,
1392
     glong        len,
1393
     glong       *items_read,
1394
     glong       *items_written,
1395
     GError     **error)
1396
0
{
1397
0
  gunichar2 *result = NULL;
1398
0
  gint n16;
1399
0
  const gchar *in;
1400
0
  gint i;
1401
1402
0
  g_return_val_if_fail (str != NULL, NULL);
1403
1404
0
  in = str;
1405
0
  n16 = 0;
1406
0
  while ((len < 0 || str + len - in > 0) && *in)
1407
0
    {
1408
0
      gunichar wc = g_utf8_get_char_extended (in, len < 0 ? 6 : str + len - in);
1409
0
      if (wc & 0x80000000)
1410
0
  {
1411
0
    if (wc == (gunichar)-2)
1412
0
      {
1413
0
        if (items_read)
1414
0
    break;
1415
0
        else
1416
0
    g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
1417
0
                                     _("Partial character sequence at end of input"));
1418
0
      }
1419
0
    else
1420
0
      g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1421
0
                                 _("Invalid byte sequence in conversion input"));
1422
1423
0
    goto err_out;
1424
0
  }
1425
1426
0
      if (wc < 0xd800)
1427
0
  n16 += 1;
1428
0
      else if (wc < 0xe000)
1429
0
  {
1430
0
    g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1431
0
                               _("Invalid sequence in conversion input"));
1432
1433
0
    goto err_out;
1434
0
  }
1435
0
      else if (wc < 0x10000)
1436
0
  n16 += 1;
1437
0
      else if (wc < 0x110000)
1438
0
  n16 += 2;
1439
0
      else
1440
0
  {
1441
0
    g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1442
0
                               _("Character out of range for UTF-16"));
1443
1444
0
    goto err_out;
1445
0
  }
1446
      
1447
0
      in = g_utf8_next_char (in);
1448
0
    }
1449
1450
0
  result = try_malloc_n (n16 + 1, sizeof (gunichar2), error);
1451
0
  if (result == NULL)
1452
0
      goto err_out;
1453
1454
0
  in = str;
1455
0
  for (i = 0; i < n16;)
1456
0
    {
1457
0
      gunichar wc = g_utf8_get_char (in);
1458
1459
0
      if (wc < 0x10000)
1460
0
  {
1461
0
    result[i++] = wc;
1462
0
  }
1463
0
      else
1464
0
  {
1465
0
    result[i++] = (wc - 0x10000) / 0x400 + 0xd800;
1466
0
    result[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
1467
0
  }
1468
      
1469
0
      in = g_utf8_next_char (in);
1470
0
    }
1471
1472
0
  result[i] = 0;
1473
1474
0
  if (items_written)
1475
0
    *items_written = n16;
1476
1477
0
 err_out:
1478
0
  if (items_read)
1479
0
    *items_read = in - str;
1480
  
1481
0
  return result;
1482
0
}
1483
1484
/**
1485
 * g_ucs4_to_utf16:
1486
 * @str: (array length=len) (element-type gunichar): a UCS-4 encoded string
1487
 * @len: the maximum length (number of characters) of @str to use. 
1488
 *   If @len is negative, then the string is nul-terminated.
1489
 * @items_read: (out) (optional): location to store number of
1490
 *   bytes read, or `NULL`. If an error occurs then the index of the invalid
1491
 *   input is stored here.
1492
 * @items_written: (out) (optional): location to store number
1493
 *   of `gunichar2` written, or `NULL`. The value stored here does not include
1494
 *   the trailing nul.
1495
 * @error: location to store the error occurring, or `NULL` to ignore
1496
 *   errors. Any of the errors in [error@GLib.ConvertError] other than
1497
 *   [error@GLib.ConvertError.NO_CONVERSION] may occur.
1498
 *
1499
 * Convert a string from UCS-4 to UTF-16.
1500
 *
1501
 * A nul character (U+0000) will be added to the result after the converted text.
1502
 * 
1503
 * Returns: (transfer full): a pointer to a newly allocated UTF-16 string.
1504
 *   This value must be freed with [func@GLib.free].
1505
 */
1506
gunichar2 *
1507
g_ucs4_to_utf16 (const gunichar  *str,
1508
     glong            len,              
1509
     glong           *items_read,       
1510
     glong           *items_written,    
1511
     GError         **error)
1512
0
{
1513
0
  gunichar2 *result = NULL;
1514
0
  gint n16;
1515
0
  gint i, j;
1516
1517
0
  n16 = 0;
1518
0
  i = 0;
1519
0
  while ((len < 0 || i < len) && str[i])
1520
0
    {
1521
0
      gunichar wc = str[i];
1522
1523
0
      if (wc < 0xd800)
1524
0
  n16 += 1;
1525
0
      else if (wc < 0xe000)
1526
0
  {
1527
0
    g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1528
0
                               _("Invalid sequence in conversion input"));
1529
1530
0
    goto err_out;
1531
0
  }
1532
0
      else if (wc < 0x10000)
1533
0
  n16 += 1;
1534
0
      else if (wc < 0x110000)
1535
0
  n16 += 2;
1536
0
      else
1537
0
  {
1538
0
    g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
1539
0
                               _("Character out of range for UTF-16"));
1540
1541
0
    goto err_out;
1542
0
  }
1543
1544
0
      i++;
1545
0
    }
1546
1547
0
  result = try_malloc_n (n16 + 1, sizeof (gunichar2), error);
1548
0
  if (result == NULL)
1549
0
      goto err_out;
1550
1551
0
  for (i = 0, j = 0; j < n16; i++)
1552
0
    {
1553
0
      gunichar wc = str[i];
1554
1555
0
      if (wc < 0x10000)
1556
0
  {
1557
0
    result[j++] = wc;
1558
0
  }
1559
0
      else
1560
0
  {
1561
0
    result[j++] = (wc - 0x10000) / 0x400 + 0xd800;
1562
0
    result[j++] = (wc - 0x10000) % 0x400 + 0xdc00;
1563
0
  }
1564
0
    }
1565
0
  result[j] = 0;
1566
1567
0
  if (items_written)
1568
0
    *items_written = n16;
1569
  
1570
0
 err_out:
1571
0
  if (items_read)
1572
0
    *items_read = i;
1573
  
1574
0
  return result;
1575
0
}
1576
1577
/* SIMD-based UTF-8 validation originates in the c-utf8 project from
1578
 * https://github.com/c-util/c-utf8/ from the following authors:
1579
 *
1580
 *   David Rheinsberg <david@readahead.eu>
1581
 *   Evgeny Vereshchagin <evvers@ya.ru>
1582
 *   Jan Engelhardt <jengelh@inai.de>
1583
 *   Tom Gundersen <teg@jklm.no>
1584
 *
1585
 * It has been adapted for portability and integration.
1586
 * The original code is dual-licensed Apache-2.0 or LGPLv2.1+
1587
 */
1588
1589
53.5k
#define align_to(_val, _to) (((_val) + (_to) - 1) & ~((_to) - 1))
1590
1591
static inline guint8
1592
load_u8 (gconstpointer memory,
1593
         gsize         offset)
1594
428k
{
1595
428k
  return ((const guint8 *)memory)[offset];
1596
428k
}
1597
1598
#if G_GNUC_CHECK_VERSION(4,8) || defined(__clang__)
1599
214k
# define _attribute_aligned(n) __attribute__((aligned(n)))
1600
#elif defined(_MSC_VER)
1601
# define _attribute_aligned(n) __declspec(align(n))
1602
#else
1603
# define _attribute_aligned(n)
1604
#endif
1605
1606
static inline gsize
1607
load_word (gconstpointer memory,
1608
           gsize         offset)
1609
214k
{
1610
214k
#if GLIB_SIZEOF_VOID_P == 8
1611
214k
  _attribute_aligned(8) const guint8 *m = ((const guint8 *)memory) + offset;
1612
1613
214k
  return ((guint64)m[0] <<  0) | ((guint64)m[1] <<  8) |
1614
214k
         ((guint64)m[2] << 16) | ((guint64)m[3] << 24) |
1615
214k
         ((guint64)m[4] << 32) | ((guint64)m[5] << 40) |
1616
214k
         ((guint64)m[6] << 48) | ((guint64)m[7] << 56);
1617
#else
1618
  _attribute_aligned(4) const guint8 *m = ((const guint8 *)memory) + offset;
1619
1620
  return ((guint)m[0] <<  0) | ((guint)m[1] <<  8) |
1621
         ((guint)m[2] << 16) | ((guint)m[3] << 24);
1622
#endif
1623
214k
}
1624
1625
/* The following constants are truncated on 32-bit machines */
1626
214k
#define UTF8_ASCII_MASK ((gsize)0x8080808080808080L)
1627
214k
#define UTF8_ASCII_SUB  ((gsize)0x0101010101010101L)
1628
1629
static inline int
1630
utf8_word_is_ascii (gsize word)
1631
214k
{
1632
  /* True unless any byte is NULL or has the MSB set. */
1633
214k
  return ((((word - UTF8_ASCII_SUB) | word) & UTF8_ASCII_MASK) == 0);
1634
214k
}
1635
1636
static void
1637
utf8_verify_ascii (const char **strp,
1638
                   gsize       *lenp)
1639
53.5k
{
1640
53.5k
  const char *str = *strp;
1641
53.5k
  gsize len = lenp ? *lenp : strlen (str);
1642
1643
107k
  while (len > 0 && load_u8 (str, 0) < 128)
1644
53.5k
    {
1645
53.5k
      if ((gpointer) align_to ((guintptr) str, sizeof (gsize)) == str)
1646
53.5k
        {
1647
160k
          while (len >= 2 * sizeof (gsize))
1648
107k
            {
1649
107k
              if (!utf8_word_is_ascii (load_word (str, 0)) ||
1650
107k
                  !utf8_word_is_ascii (load_word (str, sizeof (gsize))))
1651
0
                break;
1652
1653
107k
              str += 2 * sizeof(gsize);
1654
107k
              len -= 2 * sizeof(gsize);
1655
107k
            }
1656
1657
214k
          while (len > 0 && load_u8 (str, 0) < 128)
1658
160k
            {
1659
160k
              if G_UNLIKELY (load_u8 (str, 0) == 0x00)
1660
0
                goto out;
1661
1662
160k
              ++str;
1663
160k
              --len;
1664
160k
            }
1665
53.5k
        }
1666
0
      else
1667
0
        {
1668
0
          if G_UNLIKELY (load_u8 (str, 0) == 0x00)
1669
0
            goto out;
1670
1671
0
          ++str;
1672
0
          --len;
1673
0
        }
1674
53.5k
    }
1675
1676
53.5k
out:
1677
53.5k
  *strp = str;
1678
1679
53.5k
  if (lenp)
1680
53.5k
    *lenp = len;
1681
53.5k
}
1682
1683
#define UTF8_CHAR_IS_TAIL(_x) (((_x) & 0xC0) == 0x80)
1684
1685
static void
1686
utf8_verify (const char **strp,
1687
             gsize       *lenp)
1688
53.5k
{
1689
53.5k
  const char *str = *strp;
1690
53.5k
  gsize len = lenp ? *lenp : strlen (str);
1691
1692
  /* See Unicode 10.0.0, Chapter 3, Section D92 */
1693
1694
107k
  while (len > 0)
1695
53.5k
    {
1696
53.5k
      guint8 b = load_u8 (str, 0);
1697
1698
53.5k
      if (b == 0x00)
1699
0
        goto out;
1700
1701
53.5k
      else if (b <= 0x7F)
1702
53.5k
        {
1703
          /*
1704
           * Special-case and optimize the ASCII case.
1705
           */
1706
53.5k
          utf8_verify_ascii ((const char **)&str, &len);
1707
53.5k
        }
1708
1709
0
      else if (b >= 0xC2 && b <= 0xDF)
1710
0
        {
1711
0
          if G_UNLIKELY (len < 2)
1712
0
            goto out;
1713
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 1)))
1714
0
            goto out;
1715
1716
0
          str += 2;
1717
0
          len -= 2;
1718
1719
0
        }
1720
1721
0
      else if (b == 0xE0)
1722
0
        {
1723
0
          if G_UNLIKELY (len < 3)
1724
0
            goto out;
1725
0
          if G_UNLIKELY (load_u8 (str, 1) < 0xA0 || load_u8 (str, 1) > 0xBF)
1726
0
            goto out;
1727
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 2)))
1728
0
            goto out;
1729
1730
0
          str += 3;
1731
0
          len -= 3;
1732
0
        }
1733
1734
0
      else if (b >= 0xE1 && b <= 0xEC)
1735
0
        {
1736
0
          if G_UNLIKELY (len < 3)
1737
0
            goto out;
1738
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 1)))
1739
0
            goto out;
1740
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 2)))
1741
0
            goto out;
1742
1743
0
          str += 3;
1744
0
          len -= 3;
1745
0
        }
1746
1747
0
      else if (b == 0xED)
1748
0
        {
1749
0
          if G_UNLIKELY (len < 3)
1750
0
            goto out;
1751
0
          if G_UNLIKELY (load_u8 (str, 1) < 0x80 || load_u8 (str, 1) > 0x9F)
1752
0
            goto out;
1753
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 2)))
1754
0
            goto out;
1755
1756
0
          str += 3;
1757
0
          len -= 3;
1758
0
        }
1759
1760
0
      else if (b >= 0xEE && b <= 0xEF)
1761
0
        {
1762
0
          if G_UNLIKELY (len < 3)
1763
0
            goto out;
1764
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 1)))
1765
0
            goto out;
1766
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 2)))
1767
0
            goto out;
1768
1769
0
          str += 3;
1770
0
          len -= 3;
1771
0
        }
1772
1773
0
      else if (b == 0xF0)
1774
0
        {
1775
0
          if G_UNLIKELY (len < 4)
1776
0
            goto out;
1777
0
          if G_UNLIKELY (load_u8 (str, 1) < 0x90 || load_u8 (str, 1) > 0xBF)
1778
0
            goto out;
1779
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 2)))
1780
0
            goto out;
1781
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 3)))
1782
0
            goto out;
1783
1784
0
          str += 4;
1785
0
          len -= 4;
1786
0
        }
1787
1788
0
      else if (b >= 0xF1 && b <= 0xF3)
1789
0
        {
1790
0
          if G_UNLIKELY (len < 4)
1791
0
            goto out;
1792
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 1)))
1793
0
            goto out;
1794
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 2)))
1795
0
            goto out;
1796
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 3)))
1797
0
            goto out;
1798
1799
0
          str += 4;
1800
0
          len -= 4;
1801
0
        }
1802
1803
0
      else if (b == 0xF4)
1804
0
        {
1805
0
          if G_UNLIKELY (len < 4)
1806
0
            goto out;
1807
0
          if G_UNLIKELY (load_u8 (str, 1) < 0x80 || load_u8 (str, 1) > 0x8F)
1808
0
            goto out;
1809
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 2)))
1810
0
            goto out;
1811
0
          if G_UNLIKELY (!UTF8_CHAR_IS_TAIL (load_u8 (str, 3)))
1812
0
            goto out;
1813
1814
0
          str += 4;
1815
0
          len -= 4;
1816
0
        }
1817
1818
0
      else goto out;
1819
53.5k
    }
1820
1821
53.5k
out:
1822
53.5k
  *strp = str;
1823
1824
53.5k
  if (lenp)
1825
53.5k
    *lenp = len;
1826
53.5k
}
1827
1828
/**
1829
 * g_utf8_validate:
1830
 * @str: (array length=max_len) (element-type guint8): a pointer to character data
1831
 * @max_len: max bytes to validate, or `-1` to go until nul
1832
 * @end: (out) (optional) (transfer none): return location for end of valid data
1833
 * 
1834
 * Validates UTF-8 encoded text.
1835
 *
1836
 * @str is the text to validate; if @str is nul-terminated, then @max_len can be
1837
 * `-1`, otherwise @max_len should be the number of bytes to validate.
1838
 *
1839
 * If @end is non-`NULL`, then the end of the valid range will be stored there.
1840
 * This is the first byte of the first invalid character if some bytes were
1841
 * invalid, or the end of the text being validated otherwise — either the
1842
 * trailing nul byte, or the first byte beyond @max_len (if it’s positive).
1843
 *
1844
 * Note that `g_utf8_validate()` returns `FALSE` if @max_len is  positive and
1845
 * any of the @max_len bytes are nul.
1846
 *
1847
 * Returns `TRUE` if all of @str was valid. Many GLib and GTK
1848
 * routines require valid UTF-8 as input; so data read from a file
1849
 * or the network should be checked with `g_utf8_validate()` before
1850
 * doing anything else with it.
1851
 * 
1852
 * Returns: `TRUE` if the text was valid UTF-8
1853
 */
1854
gboolean
1855
g_utf8_validate (const char   *str,
1856
                 gssize        max_len,
1857
                 const gchar **end)
1858
53.5k
{
1859
53.5k
  size_t max_len_unsigned = (max_len >= 0) ? (size_t) max_len : strlen (str);
1860
1861
53.5k
  return g_utf8_validate_len (str, max_len_unsigned, end);
1862
53.5k
}
1863
1864
/**
1865
 * g_utf8_validate_len:
1866
 * @str: (array length=max_len) (element-type guint8): a pointer to character data
1867
 * @max_len: max bytes to validate
1868
 * @end: (out) (optional) (transfer none): return location for end of valid data
1869
 *
1870
 * Validates UTF-8 encoded text.
1871
 *
1872
 * As with [func@GLib.utf8_validate], but @max_len must be set, and hence this
1873
 * function will always return `FALSE` if any of the bytes of @str are nul.
1874
 *
1875
 * Returns: `TRUE` if the text was valid UTF-8
1876
 * Since: 2.60
1877
 */
1878
gboolean
1879
g_utf8_validate_len (const char   *str,
1880
                     gsize         max_len,
1881
                     const gchar **end)
1882
1883
53.5k
{
1884
53.5k
  utf8_verify (&str, &max_len);
1885
1886
53.5k
  if (end != NULL)
1887
0
    *end = str;
1888
1889
53.5k
  return max_len == 0;
1890
53.5k
}
1891
1892
/**
1893
 * g_str_is_ascii:
1894
 * @str: a string
1895
 *
1896
 * Determines if a string is pure ASCII. A string is pure ASCII if it
1897
 * contains no bytes with the high bit set.
1898
 *
1899
 * Returns: true if @str is ASCII
1900
 *
1901
 * Since: 2.40
1902
 */
1903
gboolean
1904
g_str_is_ascii (const gchar *str)
1905
0
{
1906
0
  utf8_verify_ascii (&str, NULL);
1907
1908
0
  return *str == 0;
1909
0
}
1910
1911
/**
1912
 * g_unichar_validate:
1913
 * @ch: a Unicode character
1914
 * 
1915
 * Checks whether @ch is a valid Unicode character.
1916
 *
1917
 * Some possible integer values of @ch will not be valid. U+0000 is considered a
1918
 * valid character, though it’s normally a string terminator.
1919
 * 
1920
 * Returns: `TRUE` if @ch is a valid Unicode character
1921
 **/
1922
gboolean
1923
g_unichar_validate (gunichar ch)
1924
0
{
1925
0
  return UNICODE_VALID (ch);
1926
0
}
1927
1928
/**
1929
 * g_utf8_strreverse:
1930
 * @str: a UTF-8 encoded string
1931
 * @len: the maximum length of @str to use, in bytes. If @len is negative,
1932
 *   then the string is nul-terminated.
1933
 *
1934
 * Reverses a UTF-8 string.
1935
 *
1936
 * @str must be valid UTF-8 encoded text. (Use [func@GLib.utf8_validate] on all
1937
 * text before trying to use UTF-8 utility functions with it.)
1938
 *
1939
 * This function is intended for programmatic uses of reversed strings.
1940
 * It pays no attention to decomposed characters, combining marks, byte 
1941
 * order marks, directional indicators (LRM, LRO, etc) and similar 
1942
 * characters which might need special handling when reversing a string 
1943
 * for display purposes.
1944
 *
1945
 * Note that unlike [func@GLib.strreverse], this function returns
1946
 * newly-allocated memory, which should be freed with [func@GLib.free] when
1947
 * no longer needed. 
1948
 *
1949
 * Returns: (transfer full): a newly-allocated string which is the reverse of @str
1950
 *
1951
 * Since: 2.2
1952
 */
1953
gchar *
1954
g_utf8_strreverse (const gchar *str,
1955
       gssize       len)
1956
0
{
1957
0
  gchar *r, *result;
1958
0
  const gchar *p;
1959
1960
0
  if (len < 0)
1961
0
    len = strlen (str);
1962
1963
0
  result = g_new (gchar, len + 1);
1964
0
  r = result + len;
1965
0
  p = str;
1966
0
  while (r > result)
1967
0
    {
1968
0
      gchar *m, skip = g_utf8_skip[*(guchar*) p];
1969
0
      r -= skip;
1970
0
      g_assert (r >= result);
1971
0
      for (m = r; skip; skip--)
1972
0
        *m++ = *p++;
1973
0
    }
1974
0
  result[len] = 0;
1975
1976
0
  return result;
1977
0
}
1978
1979
/**
1980
 * g_utf8_make_valid:
1981
 * @str: string to coerce into UTF-8
1982
 * @len: the maximum length of @str to use, in bytes. If @len is negative,
1983
 *   then the string is nul-terminated.
1984
 *
1985
 * If the provided string is valid UTF-8, return a copy of it. If not,
1986
 * return a copy in which bytes that could not be interpreted as valid Unicode
1987
 * are replaced with the Unicode replacement character (U+FFFD).
1988
 *
1989
 * For example, this is an appropriate function to use if you have received
1990
 * a string that was incorrectly declared to be UTF-8, and you need a valid
1991
 * UTF-8 version of it that can be logged or displayed to the user, with the
1992
 * assumption that it is close enough to ASCII or UTF-8 to be mostly
1993
 * readable as-is.
1994
 *
1995
 * Returns: (transfer full): a valid UTF-8 string whose content resembles @str
1996
 *
1997
 * Since: 2.52
1998
 */
1999
gchar *
2000
g_utf8_make_valid (const gchar *str,
2001
                   gssize       len)
2002
0
{
2003
0
  GString *string;
2004
0
  const gchar *remainder, *invalid;
2005
0
  gsize remaining_bytes, valid_bytes;
2006
2007
0
  g_return_val_if_fail (str != NULL, NULL);
2008
2009
0
  if (len < 0)
2010
0
    len = strlen (str);
2011
2012
0
  string = NULL;
2013
0
  remainder = str;
2014
0
  remaining_bytes = len;
2015
2016
0
  while (remaining_bytes != 0) 
2017
0
    {
2018
0
      if (g_utf8_validate (remainder, remaining_bytes, &invalid)) 
2019
0
  break;
2020
0
      valid_bytes = invalid - remainder;
2021
    
2022
0
      if (string == NULL) 
2023
0
  string = g_string_sized_new (remaining_bytes);
2024
2025
0
      g_string_append_len (string, remainder, valid_bytes);
2026
      /* append U+FFFD REPLACEMENT CHARACTER */
2027
0
      g_string_append (string, "\357\277\275");
2028
      
2029
0
      remaining_bytes -= valid_bytes + 1;
2030
0
      remainder = invalid + 1;
2031
0
    }
2032
  
2033
0
  if (string == NULL)
2034
0
    return g_strndup (str, len);
2035
  
2036
0
  g_string_append_len (string, remainder, remaining_bytes);
2037
0
  g_string_append_c (string, '\0');
2038
2039
0
  g_assert (g_utf8_validate (string->str, -1, NULL));
2040
2041
0
  return g_string_free (string, FALSE);
2042
0
}