Coverage Report

Created: 2026-08-14 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libunistring/lib/uninorm/u-normalize-internal.h
Line
Count
Source
1
/* Decomposition and composition of Unicode strings.
2
   Copyright (C) 2009-2026 Free Software Foundation, Inc.
3
   Written by Bruno Haible <bruno@clisp.org>, 2009.
4
5
   This file is free software: you can redistribute it and/or modify
6
   it under the terms of the GNU Lesser General Public License as
7
   published by the Free Software Foundation; either version 2.1 of the
8
   License, or (at your option) any later version.
9
10
   This file is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU Lesser General Public License for more details.
14
15
   You should have received a copy of the GNU Lesser General Public License
16
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17
18
UNIT *
19
FUNC (uninorm_t nf, const UNIT *s, size_t n,
20
      UNIT *resultbuf, size_t *lengthp)
21
39.0k
{
22
39.0k
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
39.0k
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
39.0k
  UNIT *result;
27
39.0k
  size_t allocated;
28
39.0k
  if (resultbuf == NULL)
29
39.0k
    {
30
39.0k
      result = NULL;
31
39.0k
      allocated = 0;
32
39.0k
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
39.0k
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
39.0k
  #define SORTBUF_PREALLOCATED 64
42
39.0k
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
39.0k
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
39.0k
    sortbuf_preallocated;
45
39.0k
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
39.0k
  size_t sortbuf_count = 0;
47
48
39.0k
  {
49
39.0k
    const UNIT *s_end = s + n;
50
51
39.0k
    for (;;)
52
370k
      {
53
370k
        int count;
54
370k
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
370k
        int decomposed_count;
56
57
370k
        if (s < s_end)
58
331k
          {
59
            /* Fetch the next character.  */
60
331k
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
331k
            decomposed_count = 1;
62
63
            /* Decompose it, recursively.
64
               It would be possible to precompute the recursive decomposition
65
               and store it in a table.  But this would significantly increase
66
               the size of the decomposition tables, because for example for
67
               U+1FC1 the recursive canonical decomposition and the recursive
68
               compatibility decomposition are different.  */
69
691k
            for (int curr = 0; curr < decomposed_count; )
70
360k
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
360k
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
360k
                int curr_decomposed_count;
75
76
360k
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
360k
                if (curr_decomposed_count >= 0)
78
14.5k
                  {
79
                    /* Move curr_decomposed[0..curr_decomposed_count-1] over
80
                       decomposed[curr], making room.  It's not worth using
81
                       memcpy() here, since the counts are so small.  */
82
14.5k
                    int shift = curr_decomposed_count - 1;
83
84
14.5k
                    if (shift < 0)
85
0
                      abort ();
86
14.5k
                    if (shift > 0)
87
14.3k
                      {
88
14.3k
                        decomposed_count += shift;
89
14.3k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
20.0k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
5.74k
                          decomposed[j + shift] = decomposed[j];
93
14.3k
                      }
94
43.4k
                    for (; shift >= 0; shift--)
95
28.8k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
14.5k
                  }
97
345k
                else
98
345k
                  {
99
                    /* decomposed[curr] is atomic.  */
100
345k
                    curr++;
101
345k
                  }
102
360k
              }
103
331k
          }
104
39.0k
        else
105
39.0k
          {
106
39.0k
            count = 0;
107
39.0k
            decomposed_count = 0;
108
39.0k
          }
109
110
370k
        int i = 0;
111
370k
        for (;;)
112
716k
          {
113
716k
            ucs4_t uc;
114
716k
            int ccc;
115
116
716k
            if (s < s_end)
117
677k
              {
118
                /* Fetch the next character from the decomposition.  */
119
677k
                if (i == decomposed_count)
120
331k
                  break;
121
345k
                uc = decomposed[i];
122
345k
                ccc = uc_combining_class (uc);
123
345k
              }
124
39.0k
            else
125
39.0k
              {
126
                /* End of string reached.  */
127
39.0k
                uc = 0;
128
39.0k
                ccc = 0;
129
39.0k
              }
130
131
384k
            if (ccc == 0)
132
330k
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
330k
                if (sortbuf_count > 1)
136
11.9k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
11.9k
                                                           sortbuf + sortbuf_count);
138
139
330k
                if (composer != NULL)
140
330k
                  {
141
                    /* Attempt to combine decomposed characters, as specified
142
                       in the Unicode Standard Annex #15 "Unicode Normalization
143
                       Forms".  We need to check
144
                         1. whether the first accumulated character is a
145
                            "starter" (i.e. has ccc = 0).  This is usually the
146
                            case.  But when the string starts with a
147
                            non-starter, the sortbuf also starts with a
148
                            non-starter.  Btw, this check could also be
149
                            omitted, because the composition table has only
150
                            entries (code1, code2) for which code1 is a
151
                            starter; if the first accumulated character is not
152
                            a starter, no lookup will succeed.
153
                         2. If the sortbuf has more than one character, check
154
                            for each of these characters that are not "blocked"
155
                            from the starter (i.e. have a ccc that is higher
156
                            than the ccc of the previous character) whether it
157
                            can be combined with the first character.
158
                         3. If only one character is left in sortbuf, check
159
                            whether it can be combined with the next character
160
                            (also a starter).  */
161
330k
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
291k
                      {
163
344k
                        for (size_t j = 1; j < sortbuf_count; )
164
53.1k
                          {
165
53.1k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
25.5k
                              {
167
25.5k
                                ucs4_t combined =
168
25.5k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
25.5k
                                if (combined)
170
10.3k
                                  {
171
10.3k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
35.4k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
25.0k
                                      sortbuf[k - 1] = sortbuf[k];
175
10.3k
                                    sortbuf_count--;
176
10.3k
                                    continue;
177
10.3k
                                  }
178
25.5k
                              }
179
42.8k
                            j++;
180
42.8k
                          }
181
291k
                        if (s < s_end && sortbuf_count == 1)
182
246k
                          {
183
246k
                            ucs4_t combined =
184
246k
                              composer (sortbuf[0].code, uc);
185
246k
                            if (combined)
186
3.19k
                              {
187
3.19k
                                uc = combined;
188
3.19k
                                ccc = 0;
189
                                /* uc could be further combined with subsequent
190
                                   characters.  So don't put it into sortbuf[0] in
191
                                   this round, only in the next round.  */
192
3.19k
                                sortbuf_count = 0;
193
3.19k
                              }
194
246k
                          }
195
291k
                      }
196
330k
                  }
197
198
662k
                for (size_t j = 0; j < sortbuf_count; j++)
199
332k
                  {
200
332k
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
332k
                    if (length < allocated)
204
292k
                      {
205
292k
                        int ret =
206
292k
                          U_UCTOMB (result + length, muc, allocated - length);
207
292k
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
292k
                        if (ret >= 0)
213
292k
                          {
214
292k
                            length += ret;
215
292k
                            goto done_appending;
216
292k
                          }
217
292k
                      }
218
39.4k
                    {
219
39.4k
                      size_t old_allocated = allocated;
220
39.4k
                      size_t new_allocated = 2 * old_allocated;
221
39.4k
                      if (new_allocated < 64)
222
38.4k
                        new_allocated = 64;
223
39.4k
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
39.4k
                      {
226
39.4k
                        UNIT *larger_result;
227
39.4k
                        if (result == NULL)
228
38.4k
                          {
229
38.4k
                            larger_result =
230
38.4k
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
38.4k
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
38.4k
                          }
237
1.05k
                        else if (result == resultbuf)
238
0
                          {
239
0
                            larger_result =
240
0
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
241
0
                            if (larger_result == NULL)
242
0
                              {
243
0
                                errno = ENOMEM;
244
0
                                goto fail;
245
0
                              }
246
0
                            U_CPY (larger_result, resultbuf, length);
247
0
                          }
248
1.05k
                        else
249
1.05k
                          {
250
1.05k
                            larger_result =
251
1.05k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
1.05k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
1.05k
                          }
258
39.4k
                        result = larger_result;
259
39.4k
                        allocated = new_allocated;
260
39.4k
                        {
261
39.4k
                          int ret =
262
39.4k
                            U_UCTOMB (result + length, muc, allocated - length);
263
39.4k
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
39.4k
                          if (ret < 0)
269
0
                            abort ();
270
39.4k
                          length += ret;
271
39.4k
                          goto done_appending;
272
39.4k
                        }
273
39.4k
                      }
274
39.4k
                    }
275
332k
                   done_appending: ;
276
332k
                  }
277
278
                /* sortbuf is now empty.  */
279
330k
                sortbuf_count = 0;
280
330k
              }
281
282
384k
            if (!(s < s_end))
283
              /* End of string reached.  */
284
39.0k
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
345k
            if (sortbuf_count == sortbuf_allocated)
288
178
              {
289
178
                sortbuf_allocated = 2 * sortbuf_allocated;
290
178
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
178
                struct ucs4_with_ccc *new_sortbuf =
293
178
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
178
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
178
                memcpy (new_sortbuf, sortbuf,
300
178
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
178
                if (sortbuf != sortbuf_preallocated)
302
178
                  free (sortbuf);
303
178
                sortbuf = new_sortbuf;
304
178
              }
305
345k
            sortbuf[sortbuf_count].code = uc;
306
345k
            sortbuf[sortbuf_count].ccc = ccc;
307
345k
            sortbuf_count++;
308
309
345k
            i++;
310
345k
          }
311
312
370k
        if (!(s < s_end))
313
          /* End of string reached.  */
314
39.0k
          break;
315
316
331k
        s += count;
317
331k
      }
318
39.0k
  }
319
320
39.0k
  if (length == 0)
321
609
    {
322
609
      if (result == NULL)
323
609
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
609
          result = (UNIT *) malloc (1);
326
609
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
609
        }
332
609
    }
333
38.4k
  else if (result != resultbuf && length < allocated)
334
38.3k
    {
335
      /* Shrink the allocated memory if possible.  */
336
38.3k
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
38.3k
      if (memory != NULL)
338
38.3k
        result = memory;
339
38.3k
    }
340
341
39.0k
  if (sortbuf_count > 0)
342
0
    abort ();
343
39.0k
  if (sortbuf != sortbuf_preallocated)
344
39.0k
    free (sortbuf);
345
346
39.0k
  *lengthp = length;
347
39.0k
  return result;
348
349
0
 fail:
350
0
  {
351
0
    int saved_errno = errno;
352
0
    if (sortbuf != sortbuf_preallocated)
353
0
      free (sortbuf);
354
0
    if (result != resultbuf)
355
0
      free (result);
356
0
    errno = saved_errno;
357
0
  }
358
  return NULL;
359
39.0k
}
u16_normalize
Line
Count
Source
21
10.3k
{
22
10.3k
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
10.3k
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
10.3k
  UNIT *result;
27
10.3k
  size_t allocated;
28
10.3k
  if (resultbuf == NULL)
29
10.3k
    {
30
10.3k
      result = NULL;
31
10.3k
      allocated = 0;
32
10.3k
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
10.3k
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
10.3k
  #define SORTBUF_PREALLOCATED 64
42
10.3k
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
10.3k
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
10.3k
    sortbuf_preallocated;
45
10.3k
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
10.3k
  size_t sortbuf_count = 0;
47
48
10.3k
  {
49
10.3k
    const UNIT *s_end = s + n;
50
51
10.3k
    for (;;)
52
57.4k
      {
53
57.4k
        int count;
54
57.4k
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
57.4k
        int decomposed_count;
56
57
57.4k
        if (s < s_end)
58
47.0k
          {
59
            /* Fetch the next character.  */
60
47.0k
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
47.0k
            decomposed_count = 1;
62
63
            /* Decompose it, recursively.
64
               It would be possible to precompute the recursive decomposition
65
               and store it in a table.  But this would significantly increase
66
               the size of the decomposition tables, because for example for
67
               U+1FC1 the recursive canonical decomposition and the recursive
68
               compatibility decomposition are different.  */
69
94.1k
            for (int curr = 0; curr < decomposed_count; )
70
47.0k
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
47.0k
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
47.0k
                int curr_decomposed_count;
75
76
47.0k
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
47.0k
                if (curr_decomposed_count >= 0)
78
0
                  {
79
                    /* Move curr_decomposed[0..curr_decomposed_count-1] over
80
                       decomposed[curr], making room.  It's not worth using
81
                       memcpy() here, since the counts are so small.  */
82
0
                    int shift = curr_decomposed_count - 1;
83
84
0
                    if (shift < 0)
85
0
                      abort ();
86
0
                    if (shift > 0)
87
0
                      {
88
0
                        decomposed_count += shift;
89
0
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
0
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
0
                          decomposed[j + shift] = decomposed[j];
93
0
                      }
94
0
                    for (; shift >= 0; shift--)
95
0
                      decomposed[curr + shift] = curr_decomposed[shift];
96
0
                  }
97
47.0k
                else
98
47.0k
                  {
99
                    /* decomposed[curr] is atomic.  */
100
47.0k
                    curr++;
101
47.0k
                  }
102
47.0k
              }
103
47.0k
          }
104
10.3k
        else
105
10.3k
          {
106
10.3k
            count = 0;
107
10.3k
            decomposed_count = 0;
108
10.3k
          }
109
110
57.4k
        int i = 0;
111
57.4k
        for (;;)
112
104k
          {
113
104k
            ucs4_t uc;
114
104k
            int ccc;
115
116
104k
            if (s < s_end)
117
94.1k
              {
118
                /* Fetch the next character from the decomposition.  */
119
94.1k
                if (i == decomposed_count)
120
47.0k
                  break;
121
47.0k
                uc = decomposed[i];
122
47.0k
                ccc = uc_combining_class (uc);
123
47.0k
              }
124
10.3k
            else
125
10.3k
              {
126
                /* End of string reached.  */
127
10.3k
                uc = 0;
128
10.3k
                ccc = 0;
129
10.3k
              }
130
131
57.4k
            if (ccc == 0)
132
57.4k
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
57.4k
                if (sortbuf_count > 1)
136
0
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
0
                                                           sortbuf + sortbuf_count);
138
139
57.4k
                if (composer != NULL)
140
57.4k
                  {
141
                    /* Attempt to combine decomposed characters, as specified
142
                       in the Unicode Standard Annex #15 "Unicode Normalization
143
                       Forms".  We need to check
144
                         1. whether the first accumulated character is a
145
                            "starter" (i.e. has ccc = 0).  This is usually the
146
                            case.  But when the string starts with a
147
                            non-starter, the sortbuf also starts with a
148
                            non-starter.  Btw, this check could also be
149
                            omitted, because the composition table has only
150
                            entries (code1, code2) for which code1 is a
151
                            starter; if the first accumulated character is not
152
                            a starter, no lookup will succeed.
153
                         2. If the sortbuf has more than one character, check
154
                            for each of these characters that are not "blocked"
155
                            from the starter (i.e. have a ccc that is higher
156
                            than the ccc of the previous character) whether it
157
                            can be combined with the first character.
158
                         3. If only one character is left in sortbuf, check
159
                            whether it can be combined with the next character
160
                            (also a starter).  */
161
57.4k
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
47.0k
                      {
163
47.0k
                        for (size_t j = 1; j < sortbuf_count; )
164
0
                          {
165
0
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
0
                              {
167
0
                                ucs4_t combined =
168
0
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
0
                                if (combined)
170
0
                                  {
171
0
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
0
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
0
                                      sortbuf[k - 1] = sortbuf[k];
175
0
                                    sortbuf_count--;
176
0
                                    continue;
177
0
                                  }
178
0
                              }
179
0
                            j++;
180
0
                          }
181
47.0k
                        if (s < s_end && sortbuf_count == 1)
182
36.7k
                          {
183
36.7k
                            ucs4_t combined =
184
36.7k
                              composer (sortbuf[0].code, uc);
185
36.7k
                            if (combined)
186
0
                              {
187
0
                                uc = combined;
188
0
                                ccc = 0;
189
                                /* uc could be further combined with subsequent
190
                                   characters.  So don't put it into sortbuf[0] in
191
                                   this round, only in the next round.  */
192
0
                                sortbuf_count = 0;
193
0
                              }
194
36.7k
                          }
195
47.0k
                      }
196
57.4k
                  }
197
198
104k
                for (size_t j = 0; j < sortbuf_count; j++)
199
47.0k
                  {
200
47.0k
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
47.0k
                    if (length < allocated)
204
36.7k
                      {
205
36.7k
                        int ret =
206
36.7k
                          U_UCTOMB (result + length, muc, allocated - length);
207
36.7k
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
36.7k
                        if (ret >= 0)
213
36.7k
                          {
214
36.7k
                            length += ret;
215
36.7k
                            goto done_appending;
216
36.7k
                          }
217
36.7k
                      }
218
10.3k
                    {
219
10.3k
                      size_t old_allocated = allocated;
220
10.3k
                      size_t new_allocated = 2 * old_allocated;
221
10.3k
                      if (new_allocated < 64)
222
10.3k
                        new_allocated = 64;
223
10.3k
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
10.3k
                      {
226
10.3k
                        UNIT *larger_result;
227
10.3k
                        if (result == NULL)
228
10.3k
                          {
229
10.3k
                            larger_result =
230
10.3k
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
10.3k
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
10.3k
                          }
237
0
                        else if (result == resultbuf)
238
0
                          {
239
0
                            larger_result =
240
0
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
241
0
                            if (larger_result == NULL)
242
0
                              {
243
0
                                errno = ENOMEM;
244
0
                                goto fail;
245
0
                              }
246
0
                            U_CPY (larger_result, resultbuf, length);
247
0
                          }
248
0
                        else
249
0
                          {
250
0
                            larger_result =
251
0
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
0
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
0
                          }
258
10.3k
                        result = larger_result;
259
10.3k
                        allocated = new_allocated;
260
10.3k
                        {
261
10.3k
                          int ret =
262
10.3k
                            U_UCTOMB (result + length, muc, allocated - length);
263
10.3k
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
10.3k
                          if (ret < 0)
269
0
                            abort ();
270
10.3k
                          length += ret;
271
10.3k
                          goto done_appending;
272
10.3k
                        }
273
10.3k
                      }
274
10.3k
                    }
275
47.0k
                   done_appending: ;
276
47.0k
                  }
277
278
                /* sortbuf is now empty.  */
279
57.4k
                sortbuf_count = 0;
280
57.4k
              }
281
282
57.4k
            if (!(s < s_end))
283
              /* End of string reached.  */
284
10.3k
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
47.0k
            if (sortbuf_count == sortbuf_allocated)
288
0
              {
289
0
                sortbuf_allocated = 2 * sortbuf_allocated;
290
0
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
0
                struct ucs4_with_ccc *new_sortbuf =
293
0
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
0
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
0
                memcpy (new_sortbuf, sortbuf,
300
0
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
0
                if (sortbuf != sortbuf_preallocated)
302
0
                  free (sortbuf);
303
0
                sortbuf = new_sortbuf;
304
0
              }
305
47.0k
            sortbuf[sortbuf_count].code = uc;
306
47.0k
            sortbuf[sortbuf_count].ccc = ccc;
307
47.0k
            sortbuf_count++;
308
309
47.0k
            i++;
310
47.0k
          }
311
312
57.4k
        if (!(s < s_end))
313
          /* End of string reached.  */
314
10.3k
          break;
315
316
47.0k
        s += count;
317
47.0k
      }
318
10.3k
  }
319
320
10.3k
  if (length == 0)
321
0
    {
322
0
      if (result == NULL)
323
0
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
0
          result = (UNIT *) malloc (1);
326
0
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
0
        }
332
0
    }
333
10.3k
  else if (result != resultbuf && length < allocated)
334
10.3k
    {
335
      /* Shrink the allocated memory if possible.  */
336
10.3k
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
10.3k
      if (memory != NULL)
338
10.3k
        result = memory;
339
10.3k
    }
340
341
10.3k
  if (sortbuf_count > 0)
342
0
    abort ();
343
10.3k
  if (sortbuf != sortbuf_preallocated)
344
10.3k
    free (sortbuf);
345
346
10.3k
  *lengthp = length;
347
10.3k
  return result;
348
349
0
 fail:
350
0
  {
351
0
    int saved_errno = errno;
352
0
    if (sortbuf != sortbuf_preallocated)
353
0
      free (sortbuf);
354
0
    if (result != resultbuf)
355
0
      free (result);
356
0
    errno = saved_errno;
357
0
  }
358
  return NULL;
359
10.3k
}
u32_normalize
Line
Count
Source
21
28.6k
{
22
28.6k
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
28.6k
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
28.6k
  UNIT *result;
27
28.6k
  size_t allocated;
28
28.6k
  if (resultbuf == NULL)
29
28.6k
    {
30
28.6k
      result = NULL;
31
28.6k
      allocated = 0;
32
28.6k
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
28.6k
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
28.6k
  #define SORTBUF_PREALLOCATED 64
42
28.6k
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
28.6k
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
28.6k
    sortbuf_preallocated;
45
28.6k
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
28.6k
  size_t sortbuf_count = 0;
47
48
28.6k
  {
49
28.6k
    const UNIT *s_end = s + n;
50
51
28.6k
    for (;;)
52
313k
      {
53
313k
        int count;
54
313k
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
313k
        int decomposed_count;
56
57
313k
        if (s < s_end)
58
284k
          {
59
            /* Fetch the next character.  */
60
284k
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
284k
            decomposed_count = 1;
62
63
            /* Decompose it, recursively.
64
               It would be possible to precompute the recursive decomposition
65
               and store it in a table.  But this would significantly increase
66
               the size of the decomposition tables, because for example for
67
               U+1FC1 the recursive canonical decomposition and the recursive
68
               compatibility decomposition are different.  */
69
597k
            for (int curr = 0; curr < decomposed_count; )
70
313k
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
313k
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
313k
                int curr_decomposed_count;
75
76
313k
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
313k
                if (curr_decomposed_count >= 0)
78
14.5k
                  {
79
                    /* Move curr_decomposed[0..curr_decomposed_count-1] over
80
                       decomposed[curr], making room.  It's not worth using
81
                       memcpy() here, since the counts are so small.  */
82
14.5k
                    int shift = curr_decomposed_count - 1;
83
84
14.5k
                    if (shift < 0)
85
0
                      abort ();
86
14.5k
                    if (shift > 0)
87
14.3k
                      {
88
14.3k
                        decomposed_count += shift;
89
14.3k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
20.0k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
5.74k
                          decomposed[j + shift] = decomposed[j];
93
14.3k
                      }
94
43.4k
                    for (; shift >= 0; shift--)
95
28.8k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
14.5k
                  }
97
298k
                else
98
298k
                  {
99
                    /* decomposed[curr] is atomic.  */
100
298k
                    curr++;
101
298k
                  }
102
313k
              }
103
284k
          }
104
28.6k
        else
105
28.6k
          {
106
28.6k
            count = 0;
107
28.6k
            decomposed_count = 0;
108
28.6k
          }
109
110
313k
        int i = 0;
111
313k
        for (;;)
112
611k
          {
113
611k
            ucs4_t uc;
114
611k
            int ccc;
115
116
611k
            if (s < s_end)
117
583k
              {
118
                /* Fetch the next character from the decomposition.  */
119
583k
                if (i == decomposed_count)
120
284k
                  break;
121
298k
                uc = decomposed[i];
122
298k
                ccc = uc_combining_class (uc);
123
298k
              }
124
28.6k
            else
125
28.6k
              {
126
                /* End of string reached.  */
127
28.6k
                uc = 0;
128
28.6k
                ccc = 0;
129
28.6k
              }
130
131
327k
            if (ccc == 0)
132
272k
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
272k
                if (sortbuf_count > 1)
136
11.9k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
11.9k
                                                           sortbuf + sortbuf_count);
138
139
272k
                if (composer != NULL)
140
272k
                  {
141
                    /* Attempt to combine decomposed characters, as specified
142
                       in the Unicode Standard Annex #15 "Unicode Normalization
143
                       Forms".  We need to check
144
                         1. whether the first accumulated character is a
145
                            "starter" (i.e. has ccc = 0).  This is usually the
146
                            case.  But when the string starts with a
147
                            non-starter, the sortbuf also starts with a
148
                            non-starter.  Btw, this check could also be
149
                            omitted, because the composition table has only
150
                            entries (code1, code2) for which code1 is a
151
                            starter; if the first accumulated character is not
152
                            a starter, no lookup will succeed.
153
                         2. If the sortbuf has more than one character, check
154
                            for each of these characters that are not "blocked"
155
                            from the starter (i.e. have a ccc that is higher
156
                            than the ccc of the previous character) whether it
157
                            can be combined with the first character.
158
                         3. If only one character is left in sortbuf, check
159
                            whether it can be combined with the next character
160
                            (also a starter).  */
161
272k
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
244k
                      {
163
297k
                        for (size_t j = 1; j < sortbuf_count; )
164
53.1k
                          {
165
53.1k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
25.5k
                              {
167
25.5k
                                ucs4_t combined =
168
25.5k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
25.5k
                                if (combined)
170
10.3k
                                  {
171
10.3k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
35.4k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
25.0k
                                      sortbuf[k - 1] = sortbuf[k];
175
10.3k
                                    sortbuf_count--;
176
10.3k
                                    continue;
177
10.3k
                                  }
178
25.5k
                              }
179
42.8k
                            j++;
180
42.8k
                          }
181
244k
                        if (s < s_end && sortbuf_count == 1)
182
209k
                          {
183
209k
                            ucs4_t combined =
184
209k
                              composer (sortbuf[0].code, uc);
185
209k
                            if (combined)
186
3.19k
                              {
187
3.19k
                                uc = combined;
188
3.19k
                                ccc = 0;
189
                                /* uc could be further combined with subsequent
190
                                   characters.  So don't put it into sortbuf[0] in
191
                                   this round, only in the next round.  */
192
3.19k
                                sortbuf_count = 0;
193
3.19k
                              }
194
209k
                          }
195
244k
                      }
196
272k
                  }
197
198
557k
                for (size_t j = 0; j < sortbuf_count; j++)
199
285k
                  {
200
285k
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
285k
                    if (length < allocated)
204
256k
                      {
205
256k
                        int ret =
206
256k
                          U_UCTOMB (result + length, muc, allocated - length);
207
256k
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
256k
                        if (ret >= 0)
213
256k
                          {
214
256k
                            length += ret;
215
256k
                            goto done_appending;
216
256k
                          }
217
256k
                      }
218
29.1k
                    {
219
29.1k
                      size_t old_allocated = allocated;
220
29.1k
                      size_t new_allocated = 2 * old_allocated;
221
29.1k
                      if (new_allocated < 64)
222
28.0k
                        new_allocated = 64;
223
29.1k
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
29.1k
                      {
226
29.1k
                        UNIT *larger_result;
227
29.1k
                        if (result == NULL)
228
28.0k
                          {
229
28.0k
                            larger_result =
230
28.0k
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
28.0k
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
28.0k
                          }
237
1.05k
                        else if (result == resultbuf)
238
0
                          {
239
0
                            larger_result =
240
0
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
241
0
                            if (larger_result == NULL)
242
0
                              {
243
0
                                errno = ENOMEM;
244
0
                                goto fail;
245
0
                              }
246
0
                            U_CPY (larger_result, resultbuf, length);
247
0
                          }
248
1.05k
                        else
249
1.05k
                          {
250
1.05k
                            larger_result =
251
1.05k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
1.05k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
1.05k
                          }
258
29.1k
                        result = larger_result;
259
29.1k
                        allocated = new_allocated;
260
29.1k
                        {
261
29.1k
                          int ret =
262
29.1k
                            U_UCTOMB (result + length, muc, allocated - length);
263
29.1k
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
29.1k
                          if (ret < 0)
269
0
                            abort ();
270
29.1k
                          length += ret;
271
29.1k
                          goto done_appending;
272
29.1k
                        }
273
29.1k
                      }
274
29.1k
                    }
275
285k
                   done_appending: ;
276
285k
                  }
277
278
                /* sortbuf is now empty.  */
279
272k
                sortbuf_count = 0;
280
272k
              }
281
282
327k
            if (!(s < s_end))
283
              /* End of string reached.  */
284
28.6k
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
298k
            if (sortbuf_count == sortbuf_allocated)
288
178
              {
289
178
                sortbuf_allocated = 2 * sortbuf_allocated;
290
178
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
178
                struct ucs4_with_ccc *new_sortbuf =
293
178
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
178
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
178
                memcpy (new_sortbuf, sortbuf,
300
178
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
178
                if (sortbuf != sortbuf_preallocated)
302
178
                  free (sortbuf);
303
178
                sortbuf = new_sortbuf;
304
178
              }
305
298k
            sortbuf[sortbuf_count].code = uc;
306
298k
            sortbuf[sortbuf_count].ccc = ccc;
307
298k
            sortbuf_count++;
308
309
298k
            i++;
310
298k
          }
311
312
313k
        if (!(s < s_end))
313
          /* End of string reached.  */
314
28.6k
          break;
315
316
284k
        s += count;
317
284k
      }
318
28.6k
  }
319
320
28.6k
  if (length == 0)
321
609
    {
322
609
      if (result == NULL)
323
609
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
609
          result = (UNIT *) malloc (1);
326
609
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
609
        }
332
609
    }
333
28.0k
  else if (result != resultbuf && length < allocated)
334
27.9k
    {
335
      /* Shrink the allocated memory if possible.  */
336
27.9k
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
27.9k
      if (memory != NULL)
338
27.9k
        result = memory;
339
27.9k
    }
340
341
28.6k
  if (sortbuf_count > 0)
342
0
    abort ();
343
28.6k
  if (sortbuf != sortbuf_preallocated)
344
28.6k
    free (sortbuf);
345
346
28.6k
  *lengthp = length;
347
28.6k
  return result;
348
349
0
 fail:
350
0
  {
351
0
    int saved_errno = errno;
352
0
    if (sortbuf != sortbuf_preallocated)
353
0
      free (sortbuf);
354
0
    if (result != resultbuf)
355
0
      free (result);
356
0
    errno = saved_errno;
357
0
  }
358
  return NULL;
359
28.6k
}