Coverage Report

Created: 2026-09-28 06:58

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
37.7k
{
22
37.7k
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
37.7k
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
37.7k
  UNIT *result;
27
37.7k
  size_t allocated;
28
37.7k
  if (resultbuf == NULL)
29
37.7k
    {
30
37.7k
      result = NULL;
31
37.7k
      allocated = 0;
32
37.7k
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
37.7k
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
37.7k
  #define SORTBUF_PREALLOCATED 64
42
37.7k
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
37.7k
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
37.7k
    sortbuf_preallocated;
45
37.7k
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
37.7k
  size_t sortbuf_count = 0;
47
48
37.7k
  {
49
37.7k
    const UNIT *s_end = s + n;
50
51
37.7k
    for (;;)
52
366k
      {
53
366k
        int count;
54
366k
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
366k
        int decomposed_count;
56
57
366k
        if (s < s_end)
58
328k
          {
59
            /* Fetch the next character.  */
60
328k
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
328k
            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
684k
            for (int curr = 0; curr < decomposed_count; )
70
356k
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
356k
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
356k
                int curr_decomposed_count;
75
76
356k
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
356k
                if (curr_decomposed_count >= 0)
78
13.8k
                  {
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
13.8k
                    int shift = curr_decomposed_count - 1;
83
84
13.8k
                    if (shift < 0)
85
0
                      abort ();
86
13.8k
                    if (shift > 0)
87
13.6k
                      {
88
13.6k
                        decomposed_count += shift;
89
13.6k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
19.1k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
5.56k
                          decomposed[j + shift] = decomposed[j];
93
13.6k
                      }
94
41.2k
                    for (; shift >= 0; shift--)
95
27.4k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
13.8k
                  }
97
342k
                else
98
342k
                  {
99
                    /* decomposed[curr] is atomic.  */
100
342k
                    curr++;
101
342k
                  }
102
356k
              }
103
328k
          }
104
37.7k
        else
105
37.7k
          {
106
37.7k
            count = 0;
107
37.7k
            decomposed_count = 0;
108
37.7k
          }
109
110
366k
        int i = 0;
111
366k
        for (;;)
112
708k
          {
113
708k
            ucs4_t uc;
114
708k
            int ccc;
115
116
708k
            if (s < s_end)
117
670k
              {
118
                /* Fetch the next character from the decomposition.  */
119
670k
                if (i == decomposed_count)
120
328k
                  break;
121
342k
                uc = decomposed[i];
122
342k
                ccc = uc_combining_class (uc);
123
342k
              }
124
37.7k
            else
125
37.7k
              {
126
                /* End of string reached.  */
127
37.7k
                uc = 0;
128
37.7k
                ccc = 0;
129
37.7k
              }
130
131
380k
            if (ccc == 0)
132
326k
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
326k
                if (sortbuf_count > 1)
136
11.5k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
11.5k
                                                           sortbuf + sortbuf_count);
138
139
326k
                if (composer != NULL)
140
326k
                  {
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
326k
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
288k
                      {
163
340k
                        for (size_t j = 1; j < sortbuf_count; )
164
52.1k
                          {
165
52.1k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
24.7k
                              {
167
24.7k
                                ucs4_t combined =
168
24.7k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
24.7k
                                if (combined)
170
9.60k
                                  {
171
9.60k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
33.7k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
24.1k
                                      sortbuf[k - 1] = sortbuf[k];
175
9.60k
                                    sortbuf_count--;
176
9.60k
                                    continue;
177
9.60k
                                  }
178
24.7k
                              }
179
42.5k
                            j++;
180
42.5k
                          }
181
288k
                        if (s < s_end && sortbuf_count == 1)
182
244k
                          {
183
244k
                            ucs4_t combined =
184
244k
                              composer (sortbuf[0].code, uc);
185
244k
                            if (combined)
186
3.23k
                              {
187
3.23k
                                uc = combined;
188
3.23k
                                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.23k
                                sortbuf_count = 0;
193
3.23k
                              }
194
244k
                          }
195
288k
                      }
196
326k
                  }
197
198
655k
                for (size_t j = 0; j < sortbuf_count; j++)
199
329k
                  {
200
329k
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
329k
                    if (length < allocated)
204
291k
                      {
205
291k
                        int ret =
206
291k
                          U_UCTOMB (result + length, muc, allocated - length);
207
291k
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
291k
                        if (ret >= 0)
213
291k
                          {
214
291k
                            length += ret;
215
291k
                            goto done_appending;
216
291k
                          }
217
291k
                      }
218
38.2k
                    {
219
38.2k
                      size_t old_allocated = allocated;
220
38.2k
                      size_t new_allocated = 2 * old_allocated;
221
38.2k
                      if (new_allocated < 64)
222
37.1k
                        new_allocated = 64;
223
38.2k
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
38.2k
                      {
226
38.2k
                        UNIT *larger_result;
227
38.2k
                        if (result == NULL)
228
37.1k
                          {
229
37.1k
                            larger_result =
230
37.1k
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
37.1k
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
37.1k
                          }
237
1.07k
                        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.07k
                        else
249
1.07k
                          {
250
1.07k
                            larger_result =
251
1.07k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
1.07k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
1.07k
                          }
258
38.2k
                        result = larger_result;
259
38.2k
                        allocated = new_allocated;
260
38.2k
                        {
261
38.2k
                          int ret =
262
38.2k
                            U_UCTOMB (result + length, muc, allocated - length);
263
38.2k
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
38.2k
                          if (ret < 0)
269
0
                            abort ();
270
38.2k
                          length += ret;
271
38.2k
                          goto done_appending;
272
38.2k
                        }
273
38.2k
                      }
274
38.2k
                    }
275
329k
                   done_appending: ;
276
329k
                  }
277
278
                /* sortbuf is now empty.  */
279
326k
                sortbuf_count = 0;
280
326k
              }
281
282
380k
            if (!(s < s_end))
283
              /* End of string reached.  */
284
37.7k
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
342k
            if (sortbuf_count == sortbuf_allocated)
288
182
              {
289
182
                sortbuf_allocated = 2 * sortbuf_allocated;
290
182
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
182
                struct ucs4_with_ccc *new_sortbuf =
293
182
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
182
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
182
                memcpy (new_sortbuf, sortbuf,
300
182
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
182
                if (sortbuf != sortbuf_preallocated)
302
182
                  free (sortbuf);
303
182
                sortbuf = new_sortbuf;
304
182
              }
305
342k
            sortbuf[sortbuf_count].code = uc;
306
342k
            sortbuf[sortbuf_count].ccc = ccc;
307
342k
            sortbuf_count++;
308
309
342k
            i++;
310
342k
          }
311
312
366k
        if (!(s < s_end))
313
          /* End of string reached.  */
314
37.7k
          break;
315
316
328k
        s += count;
317
328k
      }
318
37.7k
  }
319
320
37.7k
  if (length == 0)
321
627
    {
322
627
      if (result == NULL)
323
627
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
627
          result = (UNIT *) malloc (1);
326
627
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
627
        }
332
627
    }
333
37.1k
  else if (result != resultbuf && length < allocated)
334
37.0k
    {
335
      /* Shrink the allocated memory if possible.  */
336
37.0k
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
37.0k
      if (memory != NULL)
338
37.0k
        result = memory;
339
37.0k
    }
340
341
37.7k
  if (sortbuf_count > 0)
342
0
    abort ();
343
37.7k
  if (sortbuf != sortbuf_preallocated)
344
37.7k
    free (sortbuf);
345
346
37.7k
  *lengthp = length;
347
37.7k
  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
37.7k
}
u16_normalize
Line
Count
Source
21
9.74k
{
22
9.74k
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
9.74k
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
9.74k
  UNIT *result;
27
9.74k
  size_t allocated;
28
9.74k
  if (resultbuf == NULL)
29
9.74k
    {
30
9.74k
      result = NULL;
31
9.74k
      allocated = 0;
32
9.74k
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
9.74k
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
9.74k
  #define SORTBUF_PREALLOCATED 64
42
9.74k
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
9.74k
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
9.74k
    sortbuf_preallocated;
45
9.74k
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
9.74k
  size_t sortbuf_count = 0;
47
48
9.74k
  {
49
9.74k
    const UNIT *s_end = s + n;
50
51
9.74k
    for (;;)
52
54.1k
      {
53
54.1k
        int count;
54
54.1k
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
54.1k
        int decomposed_count;
56
57
54.1k
        if (s < s_end)
58
44.4k
          {
59
            /* Fetch the next character.  */
60
44.4k
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
44.4k
            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
88.8k
            for (int curr = 0; curr < decomposed_count; )
70
44.4k
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
44.4k
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
44.4k
                int curr_decomposed_count;
75
76
44.4k
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
44.4k
                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
44.4k
                else
98
44.4k
                  {
99
                    /* decomposed[curr] is atomic.  */
100
44.4k
                    curr++;
101
44.4k
                  }
102
44.4k
              }
103
44.4k
          }
104
9.74k
        else
105
9.74k
          {
106
9.74k
            count = 0;
107
9.74k
            decomposed_count = 0;
108
9.74k
          }
109
110
54.1k
        int i = 0;
111
54.1k
        for (;;)
112
98.6k
          {
113
98.6k
            ucs4_t uc;
114
98.6k
            int ccc;
115
116
98.6k
            if (s < s_end)
117
88.8k
              {
118
                /* Fetch the next character from the decomposition.  */
119
88.8k
                if (i == decomposed_count)
120
44.4k
                  break;
121
44.4k
                uc = decomposed[i];
122
44.4k
                ccc = uc_combining_class (uc);
123
44.4k
              }
124
9.74k
            else
125
9.74k
              {
126
                /* End of string reached.  */
127
9.74k
                uc = 0;
128
9.74k
                ccc = 0;
129
9.74k
              }
130
131
54.1k
            if (ccc == 0)
132
54.1k
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
54.1k
                if (sortbuf_count > 1)
136
0
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
0
                                                           sortbuf + sortbuf_count);
138
139
54.1k
                if (composer != NULL)
140
54.1k
                  {
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
54.1k
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
44.4k
                      {
163
44.4k
                        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
44.4k
                        if (s < s_end && sortbuf_count == 1)
182
34.7k
                          {
183
34.7k
                            ucs4_t combined =
184
34.7k
                              composer (sortbuf[0].code, uc);
185
34.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
34.7k
                          }
195
44.4k
                      }
196
54.1k
                  }
197
198
98.6k
                for (size_t j = 0; j < sortbuf_count; j++)
199
44.4k
                  {
200
44.4k
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
44.4k
                    if (length < allocated)
204
34.7k
                      {
205
34.7k
                        int ret =
206
34.7k
                          U_UCTOMB (result + length, muc, allocated - length);
207
34.7k
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
34.7k
                        if (ret >= 0)
213
34.7k
                          {
214
34.7k
                            length += ret;
215
34.7k
                            goto done_appending;
216
34.7k
                          }
217
34.7k
                      }
218
9.74k
                    {
219
9.74k
                      size_t old_allocated = allocated;
220
9.74k
                      size_t new_allocated = 2 * old_allocated;
221
9.74k
                      if (new_allocated < 64)
222
9.74k
                        new_allocated = 64;
223
9.74k
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
9.74k
                      {
226
9.74k
                        UNIT *larger_result;
227
9.74k
                        if (result == NULL)
228
9.74k
                          {
229
9.74k
                            larger_result =
230
9.74k
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
9.74k
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
9.74k
                          }
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
9.74k
                        result = larger_result;
259
9.74k
                        allocated = new_allocated;
260
9.74k
                        {
261
9.74k
                          int ret =
262
9.74k
                            U_UCTOMB (result + length, muc, allocated - length);
263
9.74k
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
9.74k
                          if (ret < 0)
269
0
                            abort ();
270
9.74k
                          length += ret;
271
9.74k
                          goto done_appending;
272
9.74k
                        }
273
9.74k
                      }
274
9.74k
                    }
275
44.4k
                   done_appending: ;
276
44.4k
                  }
277
278
                /* sortbuf is now empty.  */
279
54.1k
                sortbuf_count = 0;
280
54.1k
              }
281
282
54.1k
            if (!(s < s_end))
283
              /* End of string reached.  */
284
9.74k
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
44.4k
            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
44.4k
            sortbuf[sortbuf_count].code = uc;
306
44.4k
            sortbuf[sortbuf_count].ccc = ccc;
307
44.4k
            sortbuf_count++;
308
309
44.4k
            i++;
310
44.4k
          }
311
312
54.1k
        if (!(s < s_end))
313
          /* End of string reached.  */
314
9.74k
          break;
315
316
44.4k
        s += count;
317
44.4k
      }
318
9.74k
  }
319
320
9.74k
  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
9.74k
  else if (result != resultbuf && length < allocated)
334
9.74k
    {
335
      /* Shrink the allocated memory if possible.  */
336
9.74k
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
9.74k
      if (memory != NULL)
338
9.74k
        result = memory;
339
9.74k
    }
340
341
9.74k
  if (sortbuf_count > 0)
342
0
    abort ();
343
9.74k
  if (sortbuf != sortbuf_preallocated)
344
9.74k
    free (sortbuf);
345
346
9.74k
  *lengthp = length;
347
9.74k
  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
9.74k
}
u32_normalize
Line
Count
Source
21
28.0k
{
22
28.0k
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
28.0k
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
28.0k
  UNIT *result;
27
28.0k
  size_t allocated;
28
28.0k
  if (resultbuf == NULL)
29
28.0k
    {
30
28.0k
      result = NULL;
31
28.0k
      allocated = 0;
32
28.0k
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
28.0k
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
28.0k
  #define SORTBUF_PREALLOCATED 64
42
28.0k
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
28.0k
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
28.0k
    sortbuf_preallocated;
45
28.0k
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
28.0k
  size_t sortbuf_count = 0;
47
48
28.0k
  {
49
28.0k
    const UNIT *s_end = s + n;
50
51
28.0k
    for (;;)
52
312k
      {
53
312k
        int count;
54
312k
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
312k
        int decomposed_count;
56
57
312k
        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
595k
            for (int curr = 0; curr < decomposed_count; )
70
311k
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
311k
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
311k
                int curr_decomposed_count;
75
76
311k
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
311k
                if (curr_decomposed_count >= 0)
78
13.8k
                  {
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
13.8k
                    int shift = curr_decomposed_count - 1;
83
84
13.8k
                    if (shift < 0)
85
0
                      abort ();
86
13.8k
                    if (shift > 0)
87
13.6k
                      {
88
13.6k
                        decomposed_count += shift;
89
13.6k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
19.1k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
5.56k
                          decomposed[j + shift] = decomposed[j];
93
13.6k
                      }
94
41.2k
                    for (; shift >= 0; shift--)
95
27.4k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
13.8k
                  }
97
297k
                else
98
297k
                  {
99
                    /* decomposed[curr] is atomic.  */
100
297k
                    curr++;
101
297k
                  }
102
311k
              }
103
284k
          }
104
28.0k
        else
105
28.0k
          {
106
28.0k
            count = 0;
107
28.0k
            decomposed_count = 0;
108
28.0k
          }
109
110
312k
        int i = 0;
111
312k
        for (;;)
112
610k
          {
113
610k
            ucs4_t uc;
114
610k
            int ccc;
115
116
610k
            if (s < s_end)
117
582k
              {
118
                /* Fetch the next character from the decomposition.  */
119
582k
                if (i == decomposed_count)
120
284k
                  break;
121
297k
                uc = decomposed[i];
122
297k
                ccc = uc_combining_class (uc);
123
297k
              }
124
28.0k
            else
125
28.0k
              {
126
                /* End of string reached.  */
127
28.0k
                uc = 0;
128
28.0k
                ccc = 0;
129
28.0k
              }
130
131
325k
            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.5k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
11.5k
                                                           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
296k
                        for (size_t j = 1; j < sortbuf_count; )
164
52.1k
                          {
165
52.1k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
24.7k
                              {
167
24.7k
                                ucs4_t combined =
168
24.7k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
24.7k
                                if (combined)
170
9.60k
                                  {
171
9.60k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
33.7k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
24.1k
                                      sortbuf[k - 1] = sortbuf[k];
175
9.60k
                                    sortbuf_count--;
176
9.60k
                                    continue;
177
9.60k
                                  }
178
24.7k
                              }
179
42.5k
                            j++;
180
42.5k
                          }
181
244k
                        if (s < s_end && sortbuf_count == 1)
182
210k
                          {
183
210k
                            ucs4_t combined =
184
210k
                              composer (sortbuf[0].code, uc);
185
210k
                            if (combined)
186
3.23k
                              {
187
3.23k
                                uc = combined;
188
3.23k
                                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.23k
                                sortbuf_count = 0;
193
3.23k
                              }
194
210k
                          }
195
244k
                      }
196
272k
                  }
197
198
557k
                for (size_t j = 0; j < sortbuf_count; j++)
199
284k
                  {
200
284k
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
284k
                    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
28.4k
                    {
219
28.4k
                      size_t old_allocated = allocated;
220
28.4k
                      size_t new_allocated = 2 * old_allocated;
221
28.4k
                      if (new_allocated < 64)
222
27.3k
                        new_allocated = 64;
223
28.4k
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
28.4k
                      {
226
28.4k
                        UNIT *larger_result;
227
28.4k
                        if (result == NULL)
228
27.3k
                          {
229
27.3k
                            larger_result =
230
27.3k
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
27.3k
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
27.3k
                          }
237
1.07k
                        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.07k
                        else
249
1.07k
                          {
250
1.07k
                            larger_result =
251
1.07k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
1.07k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
1.07k
                          }
258
28.4k
                        result = larger_result;
259
28.4k
                        allocated = new_allocated;
260
28.4k
                        {
261
28.4k
                          int ret =
262
28.4k
                            U_UCTOMB (result + length, muc, allocated - length);
263
28.4k
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
28.4k
                          if (ret < 0)
269
0
                            abort ();
270
28.4k
                          length += ret;
271
28.4k
                          goto done_appending;
272
28.4k
                        }
273
28.4k
                      }
274
28.4k
                    }
275
284k
                   done_appending: ;
276
284k
                  }
277
278
                /* sortbuf is now empty.  */
279
272k
                sortbuf_count = 0;
280
272k
              }
281
282
325k
            if (!(s < s_end))
283
              /* End of string reached.  */
284
28.0k
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
297k
            if (sortbuf_count == sortbuf_allocated)
288
182
              {
289
182
                sortbuf_allocated = 2 * sortbuf_allocated;
290
182
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
182
                struct ucs4_with_ccc *new_sortbuf =
293
182
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
182
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
182
                memcpy (new_sortbuf, sortbuf,
300
182
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
182
                if (sortbuf != sortbuf_preallocated)
302
182
                  free (sortbuf);
303
182
                sortbuf = new_sortbuf;
304
182
              }
305
297k
            sortbuf[sortbuf_count].code = uc;
306
297k
            sortbuf[sortbuf_count].ccc = ccc;
307
297k
            sortbuf_count++;
308
309
297k
            i++;
310
297k
          }
311
312
312k
        if (!(s < s_end))
313
          /* End of string reached.  */
314
28.0k
          break;
315
316
284k
        s += count;
317
284k
      }
318
28.0k
  }
319
320
28.0k
  if (length == 0)
321
627
    {
322
627
      if (result == NULL)
323
627
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
627
          result = (UNIT *) malloc (1);
326
627
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
627
        }
332
627
    }
333
27.3k
  else if (result != resultbuf && length < allocated)
334
27.3k
    {
335
      /* Shrink the allocated memory if possible.  */
336
27.3k
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
27.3k
      if (memory != NULL)
338
27.3k
        result = memory;
339
27.3k
    }
340
341
28.0k
  if (sortbuf_count > 0)
342
0
    abort ();
343
28.0k
  if (sortbuf != sortbuf_preallocated)
344
28.0k
    free (sortbuf);
345
346
28.0k
  *lengthp = length;
347
28.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
28.0k
}