Coverage Report

Created: 2026-08-20 06:19

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
10.0M
{
22
10.0M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
10.0M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
10.0M
  UNIT *result;
27
10.0M
  size_t allocated;
28
10.0M
  if (resultbuf == NULL)
29
10.0M
    {
30
10.0M
      result = NULL;
31
10.0M
      allocated = 0;
32
10.0M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
10.0M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
10.0M
  #define SORTBUF_PREALLOCATED 64
42
10.0M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
10.0M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
10.0M
    sortbuf_preallocated;
45
10.0M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
10.0M
  size_t sortbuf_count = 0;
47
48
10.0M
  {
49
10.0M
    const UNIT *s_end = s + n;
50
51
10.0M
    for (;;)
52
33.2M
      {
53
33.2M
        int count;
54
33.2M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
33.2M
        int decomposed_count;
56
57
33.2M
        if (s < s_end)
58
23.2M
          {
59
            /* Fetch the next character.  */
60
23.2M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
23.2M
            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
55.5M
            for (int curr = 0; curr < decomposed_count; )
70
32.3M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
32.3M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
32.3M
                int curr_decomposed_count;
75
76
32.3M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
32.3M
                if (curr_decomposed_count >= 0)
78
3.14M
                  {
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
3.14M
                    int shift = curr_decomposed_count - 1;
83
84
3.14M
                    if (shift < 0)
85
0
                      abort ();
86
3.14M
                    if (shift > 0)
87
2.80M
                      {
88
2.80M
                        decomposed_count += shift;
89
2.80M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.83M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
26.3k
                          decomposed[j + shift] = decomposed[j];
93
2.80M
                      }
94
12.2M
                    for (; shift >= 0; shift--)
95
9.09M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.14M
                  }
97
29.1M
                else
98
29.1M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
29.1M
                    curr++;
101
29.1M
                  }
102
32.3M
              }
103
23.2M
          }
104
10.0M
        else
105
10.0M
          {
106
10.0M
            count = 0;
107
10.0M
            decomposed_count = 0;
108
10.0M
          }
109
110
33.2M
        int i = 0;
111
33.2M
        for (;;)
112
62.4M
          {
113
62.4M
            ucs4_t uc;
114
62.4M
            int ccc;
115
116
62.4M
            if (s < s_end)
117
52.4M
              {
118
                /* Fetch the next character from the decomposition.  */
119
52.4M
                if (i == decomposed_count)
120
23.2M
                  break;
121
29.1M
                uc = decomposed[i];
122
29.1M
                ccc = uc_combining_class (uc);
123
29.1M
              }
124
10.0M
            else
125
10.0M
              {
126
                /* End of string reached.  */
127
10.0M
                uc = 0;
128
10.0M
                ccc = 0;
129
10.0M
              }
130
131
39.1M
            if (ccc == 0)
132
35.9M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
35.9M
                if (sortbuf_count > 1)
136
1.64M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.64M
                                                           sortbuf + sortbuf_count);
138
139
35.9M
                if (composer != NULL)
140
35.9M
                  {
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
35.9M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
25.9M
                      {
163
29.1M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.24M
                          {
165
3.24M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.67M
                              {
167
1.67M
                                ucs4_t combined =
168
1.67M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.67M
                                if (combined)
170
1.61M
                                  {
171
1.61M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.70M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.08M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.61M
                                    sortbuf_count--;
176
1.61M
                                    continue;
177
1.61M
                                  }
178
1.67M
                              }
179
1.62M
                            j++;
180
1.62M
                          }
181
25.9M
                        if (s < s_end && sortbuf_count == 1)
182
15.9M
                          {
183
15.9M
                            ucs4_t combined =
184
15.9M
                              composer (sortbuf[0].code, uc);
185
15.9M
                            if (combined)
186
17.6k
                              {
187
17.6k
                                uc = combined;
188
17.6k
                                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
17.6k
                                sortbuf_count = 0;
193
17.6k
                              }
194
15.9M
                          }
195
25.9M
                      }
196
35.9M
                  }
197
198
63.4M
                for (size_t j = 0; j < sortbuf_count; j++)
199
27.5M
                  {
200
27.5M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
27.5M
                    if (length < allocated)
204
17.5M
                      {
205
17.5M
                        int ret =
206
17.5M
                          U_UCTOMB (result + length, muc, allocated - length);
207
17.5M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
17.5M
                        if (ret >= 0)
213
17.5M
                          {
214
17.5M
                            length += ret;
215
17.5M
                            goto done_appending;
216
17.5M
                          }
217
17.5M
                      }
218
9.96M
                    {
219
9.96M
                      size_t old_allocated = allocated;
220
9.96M
                      size_t new_allocated = 2 * old_allocated;
221
9.96M
                      if (new_allocated < 64)
222
9.95M
                        new_allocated = 64;
223
9.96M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
9.96M
                      {
226
9.96M
                        UNIT *larger_result;
227
9.96M
                        if (result == NULL)
228
9.95M
                          {
229
9.95M
                            larger_result =
230
9.95M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
9.95M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
9.95M
                          }
237
16.5k
                        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
16.5k
                        else
249
16.5k
                          {
250
16.5k
                            larger_result =
251
16.5k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
16.5k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
16.5k
                          }
258
9.96M
                        result = larger_result;
259
9.96M
                        allocated = new_allocated;
260
9.96M
                        {
261
9.96M
                          int ret =
262
9.96M
                            U_UCTOMB (result + length, muc, allocated - length);
263
9.96M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
9.96M
                          if (ret < 0)
269
0
                            abort ();
270
9.96M
                          length += ret;
271
9.96M
                          goto done_appending;
272
9.96M
                        }
273
9.96M
                      }
274
9.96M
                    }
275
27.5M
                   done_appending: ;
276
27.5M
                  }
277
278
                /* sortbuf is now empty.  */
279
35.9M
                sortbuf_count = 0;
280
35.9M
              }
281
282
39.1M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
10.0M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
29.1M
            if (sortbuf_count == sortbuf_allocated)
288
2.27k
              {
289
2.27k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
2.27k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
2.27k
                struct ucs4_with_ccc *new_sortbuf =
293
2.27k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
2.27k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
2.27k
                memcpy (new_sortbuf, sortbuf,
300
2.27k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
2.27k
                if (sortbuf != sortbuf_preallocated)
302
2.27k
                  free (sortbuf);
303
2.27k
                sortbuf = new_sortbuf;
304
2.27k
              }
305
29.1M
            sortbuf[sortbuf_count].code = uc;
306
29.1M
            sortbuf[sortbuf_count].ccc = ccc;
307
29.1M
            sortbuf_count++;
308
309
29.1M
            i++;
310
29.1M
          }
311
312
33.2M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
10.0M
          break;
315
316
23.2M
        s += count;
317
23.2M
      }
318
10.0M
  }
319
320
10.0M
  if (length == 0)
321
64.4k
    {
322
64.4k
      if (result == NULL)
323
64.4k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
64.4k
          result = (UNIT *) malloc (1);
326
64.4k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
64.4k
        }
332
64.4k
    }
333
9.95M
  else if (result != resultbuf && length < allocated)
334
9.95M
    {
335
      /* Shrink the allocated memory if possible.  */
336
9.95M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
9.95M
      if (memory != NULL)
338
9.95M
        result = memory;
339
9.95M
    }
340
341
10.0M
  if (sortbuf_count > 0)
342
0
    abort ();
343
10.0M
  if (sortbuf != sortbuf_preallocated)
344
10.0M
    free (sortbuf);
345
346
10.0M
  *lengthp = length;
347
10.0M
  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.0M
}
u8_normalize
Line
Count
Source
21
3.32M
{
22
3.32M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
3.32M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
3.32M
  UNIT *result;
27
3.32M
  size_t allocated;
28
3.32M
  if (resultbuf == NULL)
29
3.32M
    {
30
3.32M
      result = NULL;
31
3.32M
      allocated = 0;
32
3.32M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
3.32M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
3.32M
  #define SORTBUF_PREALLOCATED 64
42
3.32M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
3.32M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
3.32M
    sortbuf_preallocated;
45
3.32M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
3.32M
  size_t sortbuf_count = 0;
47
48
3.32M
  {
49
3.32M
    const UNIT *s_end = s + n;
50
51
3.32M
    for (;;)
52
16.8M
      {
53
16.8M
        int count;
54
16.8M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
16.8M
        int decomposed_count;
56
57
16.8M
        if (s < s_end)
58
13.5M
          {
59
            /* Fetch the next character.  */
60
13.5M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
13.5M
            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
36.1M
            for (int curr = 0; curr < decomposed_count; )
70
22.5M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
22.5M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
22.5M
                int curr_decomposed_count;
75
76
22.5M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
22.5M
                if (curr_decomposed_count >= 0)
78
3.10M
                  {
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
3.10M
                    int shift = curr_decomposed_count - 1;
83
84
3.10M
                    if (shift < 0)
85
0
                      abort ();
86
3.10M
                    if (shift > 0)
87
2.77M
                      {
88
2.77M
                        decomposed_count += shift;
89
2.77M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.79M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
16.5k
                          decomposed[j + shift] = decomposed[j];
93
2.77M
                      }
94
12.1M
                    for (; shift >= 0; shift--)
95
9.03M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.10M
                  }
97
19.4M
                else
98
19.4M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
19.4M
                    curr++;
101
19.4M
                  }
102
22.5M
              }
103
13.5M
          }
104
3.32M
        else
105
3.32M
          {
106
3.32M
            count = 0;
107
3.32M
            decomposed_count = 0;
108
3.32M
          }
109
110
16.8M
        int i = 0;
111
16.8M
        for (;;)
112
36.3M
          {
113
36.3M
            ucs4_t uc;
114
36.3M
            int ccc;
115
116
36.3M
            if (s < s_end)
117
32.9M
              {
118
                /* Fetch the next character from the decomposition.  */
119
32.9M
                if (i == decomposed_count)
120
13.5M
                  break;
121
19.4M
                uc = decomposed[i];
122
19.4M
                ccc = uc_combining_class (uc);
123
19.4M
              }
124
3.32M
            else
125
3.32M
              {
126
                /* End of string reached.  */
127
3.32M
                uc = 0;
128
3.32M
                ccc = 0;
129
3.32M
              }
130
131
22.7M
            if (ccc == 0)
132
19.6M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
19.6M
                if (sortbuf_count > 1)
136
1.62M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.62M
                                                           sortbuf + sortbuf_count);
138
139
19.6M
                if (composer != NULL)
140
19.6M
                  {
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
19.6M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
16.3M
                      {
163
19.4M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.12M
                          {
165
3.12M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.64M
                              {
167
1.64M
                                ucs4_t combined =
168
1.64M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.64M
                                if (combined)
170
1.59M
                                  {
171
1.59M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.66M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.07M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.59M
                                    sortbuf_count--;
176
1.59M
                                    continue;
177
1.59M
                                  }
178
1.64M
                              }
179
1.52M
                            j++;
180
1.52M
                          }
181
16.3M
                        if (s < s_end && sortbuf_count == 1)
182
12.9M
                          {
183
12.9M
                            ucs4_t combined =
184
12.9M
                              composer (sortbuf[0].code, uc);
185
12.9M
                            if (combined)
186
8.27k
                              {
187
8.27k
                                uc = combined;
188
8.27k
                                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
8.27k
                                sortbuf_count = 0;
193
8.27k
                              }
194
12.9M
                          }
195
16.3M
                      }
196
19.6M
                  }
197
198
37.4M
                for (size_t j = 0; j < sortbuf_count; j++)
199
17.8M
                  {
200
17.8M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
17.8M
                    if (length < allocated)
204
14.5M
                      {
205
14.5M
                        int ret =
206
14.5M
                          U_UCTOMB (result + length, muc, allocated - length);
207
14.5M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
14.5M
                        if (ret >= 0)
213
14.5M
                          {
214
14.5M
                            length += ret;
215
14.5M
                            goto done_appending;
216
14.5M
                          }
217
14.5M
                      }
218
3.33M
                    {
219
3.33M
                      size_t old_allocated = allocated;
220
3.33M
                      size_t new_allocated = 2 * old_allocated;
221
3.33M
                      if (new_allocated < 64)
222
3.32M
                        new_allocated = 64;
223
3.33M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
3.33M
                      {
226
3.33M
                        UNIT *larger_result;
227
3.33M
                        if (result == NULL)
228
3.32M
                          {
229
3.32M
                            larger_result =
230
3.32M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
3.32M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
3.32M
                          }
237
13.2k
                        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
13.2k
                        else
249
13.2k
                          {
250
13.2k
                            larger_result =
251
13.2k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
13.2k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
13.2k
                          }
258
3.33M
                        result = larger_result;
259
3.33M
                        allocated = new_allocated;
260
3.33M
                        {
261
3.33M
                          int ret =
262
3.33M
                            U_UCTOMB (result + length, muc, allocated - length);
263
3.33M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
3.33M
                          if (ret < 0)
269
0
                            abort ();
270
3.33M
                          length += ret;
271
3.33M
                          goto done_appending;
272
3.33M
                        }
273
3.33M
                      }
274
3.33M
                    }
275
17.8M
                   done_appending: ;
276
17.8M
                  }
277
278
                /* sortbuf is now empty.  */
279
19.6M
                sortbuf_count = 0;
280
19.6M
              }
281
282
22.7M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
3.32M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
19.4M
            if (sortbuf_count == sortbuf_allocated)
288
1.24k
              {
289
1.24k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.24k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.24k
                struct ucs4_with_ccc *new_sortbuf =
293
1.24k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.24k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.24k
                memcpy (new_sortbuf, sortbuf,
300
1.24k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.24k
                if (sortbuf != sortbuf_preallocated)
302
1.24k
                  free (sortbuf);
303
1.24k
                sortbuf = new_sortbuf;
304
1.24k
              }
305
19.4M
            sortbuf[sortbuf_count].code = uc;
306
19.4M
            sortbuf[sortbuf_count].ccc = ccc;
307
19.4M
            sortbuf_count++;
308
309
19.4M
            i++;
310
19.4M
          }
311
312
16.8M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
3.32M
          break;
315
316
13.5M
        s += count;
317
13.5M
      }
318
3.32M
  }
319
320
3.32M
  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
3.32M
  else if (result != resultbuf && length < allocated)
334
3.32M
    {
335
      /* Shrink the allocated memory if possible.  */
336
3.32M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
3.32M
      if (memory != NULL)
338
3.32M
        result = memory;
339
3.32M
    }
340
341
3.32M
  if (sortbuf_count > 0)
342
0
    abort ();
343
3.32M
  if (sortbuf != sortbuf_preallocated)
344
3.32M
    free (sortbuf);
345
346
3.32M
  *lengthp = length;
347
3.32M
  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
3.32M
}
u32_normalize
Line
Count
Source
21
6.69M
{
22
6.69M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
6.69M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
6.69M
  UNIT *result;
27
6.69M
  size_t allocated;
28
6.69M
  if (resultbuf == NULL)
29
6.69M
    {
30
6.69M
      result = NULL;
31
6.69M
      allocated = 0;
32
6.69M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
6.69M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
6.69M
  #define SORTBUF_PREALLOCATED 64
42
6.69M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
6.69M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
6.69M
    sortbuf_preallocated;
45
6.69M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
6.69M
  size_t sortbuf_count = 0;
47
48
6.69M
  {
49
6.69M
    const UNIT *s_end = s + n;
50
51
6.69M
    for (;;)
52
16.3M
      {
53
16.3M
        int count;
54
16.3M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
16.3M
        int decomposed_count;
56
57
16.3M
        if (s < s_end)
58
9.69M
          {
59
            /* Fetch the next character.  */
60
9.69M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
9.69M
            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
19.4M
            for (int curr = 0; curr < decomposed_count; )
70
9.75M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
9.75M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
9.75M
                int curr_decomposed_count;
75
76
9.75M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
9.75M
                if (curr_decomposed_count >= 0)
78
31.3k
                  {
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
31.3k
                    int shift = curr_decomposed_count - 1;
83
84
31.3k
                    if (shift < 0)
85
0
                      abort ();
86
31.3k
                    if (shift > 0)
87
31.1k
                      {
88
31.1k
                        decomposed_count += shift;
89
31.1k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
40.9k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
9.79k
                          decomposed[j + shift] = decomposed[j];
93
31.1k
                      }
94
93.9k
                    for (; shift >= 0; shift--)
95
62.5k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
31.3k
                  }
97
9.72M
                else
98
9.72M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
9.72M
                    curr++;
101
9.72M
                  }
102
9.75M
              }
103
9.69M
          }
104
6.69M
        else
105
6.69M
          {
106
6.69M
            count = 0;
107
6.69M
            decomposed_count = 0;
108
6.69M
          }
109
110
16.3M
        int i = 0;
111
16.3M
        for (;;)
112
26.1M
          {
113
26.1M
            ucs4_t uc;
114
26.1M
            int ccc;
115
116
26.1M
            if (s < s_end)
117
19.4M
              {
118
                /* Fetch the next character from the decomposition.  */
119
19.4M
                if (i == decomposed_count)
120
9.69M
                  break;
121
9.72M
                uc = decomposed[i];
122
9.72M
                ccc = uc_combining_class (uc);
123
9.72M
              }
124
6.69M
            else
125
6.69M
              {
126
                /* End of string reached.  */
127
6.69M
                uc = 0;
128
6.69M
                ccc = 0;
129
6.69M
              }
130
131
16.4M
            if (ccc == 0)
132
16.2M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
16.2M
                if (sortbuf_count > 1)
136
23.0k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
23.0k
                                                           sortbuf + sortbuf_count);
138
139
16.2M
                if (composer != NULL)
140
16.2M
                  {
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
16.2M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
9.59M
                      {
163
9.71M
                        for (size_t j = 1; j < sortbuf_count; )
164
119k
                          {
165
119k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
33.4k
                              {
167
33.4k
                                ucs4_t combined =
168
33.4k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
33.4k
                                if (combined)
170
20.1k
                                  {
171
20.1k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
33.3k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
13.2k
                                      sortbuf[k - 1] = sortbuf[k];
175
20.1k
                                    sortbuf_count--;
176
20.1k
                                    continue;
177
20.1k
                                  }
178
33.4k
                              }
179
99.0k
                            j++;
180
99.0k
                          }
181
9.59M
                        if (s < s_end && sortbuf_count == 1)
182
2.96M
                          {
183
2.96M
                            ucs4_t combined =
184
2.96M
                              composer (sortbuf[0].code, uc);
185
2.96M
                            if (combined)
186
9.41k
                              {
187
9.41k
                                uc = combined;
188
9.41k
                                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
9.41k
                                sortbuf_count = 0;
193
9.41k
                              }
194
2.96M
                          }
195
9.59M
                      }
196
16.2M
                  }
197
198
25.9M
                for (size_t j = 0; j < sortbuf_count; j++)
199
9.69M
                  {
200
9.69M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
9.69M
                    if (length < allocated)
204
3.06M
                      {
205
3.06M
                        int ret =
206
3.06M
                          U_UCTOMB (result + length, muc, allocated - length);
207
3.06M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
3.06M
                        if (ret >= 0)
213
3.06M
                          {
214
3.06M
                            length += ret;
215
3.06M
                            goto done_appending;
216
3.06M
                          }
217
3.06M
                      }
218
6.63M
                    {
219
6.63M
                      size_t old_allocated = allocated;
220
6.63M
                      size_t new_allocated = 2 * old_allocated;
221
6.63M
                      if (new_allocated < 64)
222
6.62M
                        new_allocated = 64;
223
6.63M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
6.63M
                      {
226
6.63M
                        UNIT *larger_result;
227
6.63M
                        if (result == NULL)
228
6.62M
                          {
229
6.62M
                            larger_result =
230
6.62M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
6.62M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
6.62M
                          }
237
3.29k
                        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
3.29k
                        else
249
3.29k
                          {
250
3.29k
                            larger_result =
251
3.29k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
3.29k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
3.29k
                          }
258
6.63M
                        result = larger_result;
259
6.63M
                        allocated = new_allocated;
260
6.63M
                        {
261
6.63M
                          int ret =
262
6.63M
                            U_UCTOMB (result + length, muc, allocated - length);
263
6.63M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
6.63M
                          if (ret < 0)
269
0
                            abort ();
270
6.63M
                          length += ret;
271
6.63M
                          goto done_appending;
272
6.63M
                        }
273
6.63M
                      }
274
6.63M
                    }
275
9.69M
                   done_appending: ;
276
9.69M
                  }
277
278
                /* sortbuf is now empty.  */
279
16.2M
                sortbuf_count = 0;
280
16.2M
              }
281
282
16.4M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
6.69M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
9.72M
            if (sortbuf_count == sortbuf_allocated)
288
1.03k
              {
289
1.03k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.03k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.03k
                struct ucs4_with_ccc *new_sortbuf =
293
1.03k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.03k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.03k
                memcpy (new_sortbuf, sortbuf,
300
1.03k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.03k
                if (sortbuf != sortbuf_preallocated)
302
1.03k
                  free (sortbuf);
303
1.03k
                sortbuf = new_sortbuf;
304
1.03k
              }
305
9.72M
            sortbuf[sortbuf_count].code = uc;
306
9.72M
            sortbuf[sortbuf_count].ccc = ccc;
307
9.72M
            sortbuf_count++;
308
309
9.72M
            i++;
310
9.72M
          }
311
312
16.3M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
6.69M
          break;
315
316
9.69M
        s += count;
317
9.69M
      }
318
6.69M
  }
319
320
6.69M
  if (length == 0)
321
64.4k
    {
322
64.4k
      if (result == NULL)
323
64.4k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
64.4k
          result = (UNIT *) malloc (1);
326
64.4k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
64.4k
        }
332
64.4k
    }
333
6.62M
  else if (result != resultbuf && length < allocated)
334
6.62M
    {
335
      /* Shrink the allocated memory if possible.  */
336
6.62M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
6.62M
      if (memory != NULL)
338
6.62M
        result = memory;
339
6.62M
    }
340
341
6.69M
  if (sortbuf_count > 0)
342
0
    abort ();
343
6.69M
  if (sortbuf != sortbuf_preallocated)
344
6.69M
    free (sortbuf);
345
346
6.69M
  *lengthp = length;
347
6.69M
  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
6.69M
}