Coverage Report

Created: 2026-08-22 07:17

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
11.3M
{
22
11.3M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
11.3M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
11.3M
  UNIT *result;
27
11.3M
  size_t allocated;
28
11.3M
  if (resultbuf == NULL)
29
11.3M
    {
30
11.3M
      result = NULL;
31
11.3M
      allocated = 0;
32
11.3M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
11.3M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
11.3M
  #define SORTBUF_PREALLOCATED 64
42
11.3M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
11.3M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
11.3M
    sortbuf_preallocated;
45
11.3M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
11.3M
  size_t sortbuf_count = 0;
47
48
11.3M
  {
49
11.3M
    const UNIT *s_end = s + n;
50
51
11.3M
    for (;;)
52
36.5M
      {
53
36.5M
        int count;
54
36.5M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
36.5M
        int decomposed_count;
56
57
36.5M
        if (s < s_end)
58
25.2M
          {
59
            /* Fetch the next character.  */
60
25.2M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
25.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
60.2M
            for (int curr = 0; curr < decomposed_count; )
70
34.9M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
34.9M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
34.9M
                int curr_decomposed_count;
75
76
34.9M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
34.9M
                if (curr_decomposed_count >= 0)
78
3.23M
                  {
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.23M
                    int shift = curr_decomposed_count - 1;
83
84
3.23M
                    if (shift < 0)
85
0
                      abort ();
86
3.23M
                    if (shift > 0)
87
2.87M
                      {
88
2.87M
                        decomposed_count += shift;
89
2.87M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.90M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
26.3k
                          decomposed[j + shift] = decomposed[j];
93
2.87M
                      }
94
12.9M
                    for (; shift >= 0; shift--)
95
9.75M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.23M
                  }
97
31.7M
                else
98
31.7M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
31.7M
                    curr++;
101
31.7M
                  }
102
34.9M
              }
103
25.2M
          }
104
11.3M
        else
105
11.3M
          {
106
11.3M
            count = 0;
107
11.3M
            decomposed_count = 0;
108
11.3M
          }
109
110
36.5M
        int i = 0;
111
36.5M
        for (;;)
112
68.2M
          {
113
68.2M
            ucs4_t uc;
114
68.2M
            int ccc;
115
116
68.2M
            if (s < s_end)
117
56.9M
              {
118
                /* Fetch the next character from the decomposition.  */
119
56.9M
                if (i == decomposed_count)
120
25.2M
                  break;
121
31.7M
                uc = decomposed[i];
122
31.7M
                ccc = uc_combining_class (uc);
123
31.7M
              }
124
11.3M
            else
125
11.3M
              {
126
                /* End of string reached.  */
127
11.3M
                uc = 0;
128
11.3M
                ccc = 0;
129
11.3M
              }
130
131
43.0M
            if (ccc == 0)
132
39.7M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
39.7M
                if (sortbuf_count > 1)
136
1.66M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.66M
                                                           sortbuf + sortbuf_count);
138
139
39.7M
                if (composer != NULL)
140
39.7M
                  {
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
39.7M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
28.4M
                      {
163
31.7M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.24M
                          {
165
3.24M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.70M
                              {
167
1.70M
                                ucs4_t combined =
168
1.70M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.70M
                                if (combined)
170
1.65M
                                  {
171
1.65M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.76M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.11M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.65M
                                    sortbuf_count--;
176
1.65M
                                    continue;
177
1.65M
                                  }
178
1.70M
                              }
179
1.59M
                            j++;
180
1.59M
                          }
181
28.4M
                        if (s < s_end && sortbuf_count == 1)
182
17.1M
                          {
183
17.1M
                            ucs4_t combined =
184
17.1M
                              composer (sortbuf[0].code, uc);
185
17.1M
                            if (combined)
186
18.0k
                              {
187
18.0k
                                uc = combined;
188
18.0k
                                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
18.0k
                                sortbuf_count = 0;
193
18.0k
                              }
194
17.1M
                          }
195
28.4M
                      }
196
39.7M
                  }
197
198
69.8M
                for (size_t j = 0; j < sortbuf_count; j++)
199
30.0M
                  {
200
30.0M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
30.0M
                    if (length < allocated)
204
18.8M
                      {
205
18.8M
                        int ret =
206
18.8M
                          U_UCTOMB (result + length, muc, allocated - length);
207
18.8M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
18.8M
                        if (ret >= 0)
213
18.8M
                          {
214
18.8M
                            length += ret;
215
18.8M
                            goto done_appending;
216
18.8M
                          }
217
18.8M
                      }
218
11.2M
                    {
219
11.2M
                      size_t old_allocated = allocated;
220
11.2M
                      size_t new_allocated = 2 * old_allocated;
221
11.2M
                      if (new_allocated < 64)
222
11.2M
                        new_allocated = 64;
223
11.2M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
11.2M
                      {
226
11.2M
                        UNIT *larger_result;
227
11.2M
                        if (result == NULL)
228
11.2M
                          {
229
11.2M
                            larger_result =
230
11.2M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
11.2M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
11.2M
                          }
237
15.3k
                        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
15.3k
                        else
249
15.3k
                          {
250
15.3k
                            larger_result =
251
15.3k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
15.3k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
15.3k
                          }
258
11.2M
                        result = larger_result;
259
11.2M
                        allocated = new_allocated;
260
11.2M
                        {
261
11.2M
                          int ret =
262
11.2M
                            U_UCTOMB (result + length, muc, allocated - length);
263
11.2M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
11.2M
                          if (ret < 0)
269
0
                            abort ();
270
11.2M
                          length += ret;
271
11.2M
                          goto done_appending;
272
11.2M
                        }
273
11.2M
                      }
274
11.2M
                    }
275
30.0M
                   done_appending: ;
276
30.0M
                  }
277
278
                /* sortbuf is now empty.  */
279
39.7M
                sortbuf_count = 0;
280
39.7M
              }
281
282
43.0M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
11.3M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
31.7M
            if (sortbuf_count == sortbuf_allocated)
288
1.99k
              {
289
1.99k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.99k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.99k
                struct ucs4_with_ccc *new_sortbuf =
293
1.99k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.99k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.99k
                memcpy (new_sortbuf, sortbuf,
300
1.99k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.99k
                if (sortbuf != sortbuf_preallocated)
302
1.99k
                  free (sortbuf);
303
1.99k
                sortbuf = new_sortbuf;
304
1.99k
              }
305
31.7M
            sortbuf[sortbuf_count].code = uc;
306
31.7M
            sortbuf[sortbuf_count].ccc = ccc;
307
31.7M
            sortbuf_count++;
308
309
31.7M
            i++;
310
31.7M
          }
311
312
36.5M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
11.3M
          break;
315
316
25.2M
        s += count;
317
25.2M
      }
318
11.3M
  }
319
320
11.3M
  if (length == 0)
321
61.5k
    {
322
61.5k
      if (result == NULL)
323
61.5k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
61.5k
          result = (UNIT *) malloc (1);
326
61.5k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
61.5k
        }
332
61.5k
    }
333
11.2M
  else if (result != resultbuf && length < allocated)
334
11.2M
    {
335
      /* Shrink the allocated memory if possible.  */
336
11.2M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
11.2M
      if (memory != NULL)
338
11.2M
        result = memory;
339
11.2M
    }
340
341
11.3M
  if (sortbuf_count > 0)
342
0
    abort ();
343
11.3M
  if (sortbuf != sortbuf_preallocated)
344
11.3M
    free (sortbuf);
345
346
11.3M
  *lengthp = length;
347
11.3M
  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
11.3M
}
u8_normalize
Line
Count
Source
21
3.75M
{
22
3.75M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
3.75M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
3.75M
  UNIT *result;
27
3.75M
  size_t allocated;
28
3.75M
  if (resultbuf == NULL)
29
3.75M
    {
30
3.75M
      result = NULL;
31
3.75M
      allocated = 0;
32
3.75M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
3.75M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
3.75M
  #define SORTBUF_PREALLOCATED 64
42
3.75M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
3.75M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
3.75M
    sortbuf_preallocated;
45
3.75M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
3.75M
  size_t sortbuf_count = 0;
47
48
3.75M
  {
49
3.75M
    const UNIT *s_end = s + n;
50
51
3.75M
    for (;;)
52
18.1M
      {
53
18.1M
        int count;
54
18.1M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
18.1M
        int decomposed_count;
56
57
18.1M
        if (s < s_end)
58
14.4M
          {
59
            /* Fetch the next character.  */
60
14.4M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
14.4M
            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
38.5M
            for (int curr = 0; curr < decomposed_count; )
70
24.1M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
24.1M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
24.1M
                int curr_decomposed_count;
75
76
24.1M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
24.1M
                if (curr_decomposed_count >= 0)
78
3.20M
                  {
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.20M
                    int shift = curr_decomposed_count - 1;
83
84
3.20M
                    if (shift < 0)
85
0
                      abort ();
86
3.20M
                    if (shift > 0)
87
2.84M
                      {
88
2.84M
                        decomposed_count += shift;
89
2.84M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.86M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
16.7k
                          decomposed[j + shift] = decomposed[j];
93
2.84M
                      }
94
12.9M
                    for (; shift >= 0; shift--)
95
9.69M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.20M
                  }
97
20.9M
                else
98
20.9M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
20.9M
                    curr++;
101
20.9M
                  }
102
24.1M
              }
103
14.4M
          }
104
3.75M
        else
105
3.75M
          {
106
3.75M
            count = 0;
107
3.75M
            decomposed_count = 0;
108
3.75M
          }
109
110
18.1M
        int i = 0;
111
18.1M
        for (;;)
112
39.1M
          {
113
39.1M
            ucs4_t uc;
114
39.1M
            int ccc;
115
116
39.1M
            if (s < s_end)
117
35.3M
              {
118
                /* Fetch the next character from the decomposition.  */
119
35.3M
                if (i == decomposed_count)
120
14.4M
                  break;
121
20.9M
                uc = decomposed[i];
122
20.9M
                ccc = uc_combining_class (uc);
123
20.9M
              }
124
3.75M
            else
125
3.75M
              {
126
                /* End of string reached.  */
127
3.75M
                uc = 0;
128
3.75M
                ccc = 0;
129
3.75M
              }
130
131
24.6M
            if (ccc == 0)
132
21.5M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
21.5M
                if (sortbuf_count > 1)
136
1.64M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.64M
                                                           sortbuf + sortbuf_count);
138
139
21.5M
                if (composer != NULL)
140
21.5M
                  {
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
21.5M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
17.7M
                      {
163
20.9M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.15M
                          {
165
3.15M
                            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.63M
                                  {
171
1.63M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.73M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.09M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.63M
                                    sortbuf_count--;
176
1.63M
                                    continue;
177
1.63M
                                  }
178
1.67M
                              }
179
1.51M
                            j++;
180
1.51M
                          }
181
17.7M
                        if (s < s_end && sortbuf_count == 1)
182
13.9M
                          {
183
13.9M
                            ucs4_t combined =
184
13.9M
                              composer (sortbuf[0].code, uc);
185
13.9M
                            if (combined)
186
8.84k
                              {
187
8.84k
                                uc = combined;
188
8.84k
                                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.84k
                                sortbuf_count = 0;
193
8.84k
                              }
194
13.9M
                          }
195
17.7M
                      }
196
21.5M
                  }
197
198
40.8M
                for (size_t j = 0; j < sortbuf_count; j++)
199
19.2M
                  {
200
19.2M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
19.2M
                    if (length < allocated)
204
15.5M
                      {
205
15.5M
                        int ret =
206
15.5M
                          U_UCTOMB (result + length, muc, allocated - length);
207
15.5M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
15.5M
                        if (ret >= 0)
213
15.5M
                          {
214
15.5M
                            length += ret;
215
15.5M
                            goto done_appending;
216
15.5M
                          }
217
15.5M
                      }
218
3.76M
                    {
219
3.76M
                      size_t old_allocated = allocated;
220
3.76M
                      size_t new_allocated = 2 * old_allocated;
221
3.76M
                      if (new_allocated < 64)
222
3.75M
                        new_allocated = 64;
223
3.76M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
3.76M
                      {
226
3.76M
                        UNIT *larger_result;
227
3.76M
                        if (result == NULL)
228
3.75M
                          {
229
3.75M
                            larger_result =
230
3.75M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
3.75M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
3.75M
                          }
237
12.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
12.5k
                        else
249
12.5k
                          {
250
12.5k
                            larger_result =
251
12.5k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
12.5k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
12.5k
                          }
258
3.76M
                        result = larger_result;
259
3.76M
                        allocated = new_allocated;
260
3.76M
                        {
261
3.76M
                          int ret =
262
3.76M
                            U_UCTOMB (result + length, muc, allocated - length);
263
3.76M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
3.76M
                          if (ret < 0)
269
0
                            abort ();
270
3.76M
                          length += ret;
271
3.76M
                          goto done_appending;
272
3.76M
                        }
273
3.76M
                      }
274
3.76M
                    }
275
19.2M
                   done_appending: ;
276
19.2M
                  }
277
278
                /* sortbuf is now empty.  */
279
21.5M
                sortbuf_count = 0;
280
21.5M
              }
281
282
24.6M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
3.75M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
20.9M
            if (sortbuf_count == sortbuf_allocated)
288
1.17k
              {
289
1.17k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.17k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.17k
                struct ucs4_with_ccc *new_sortbuf =
293
1.17k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.17k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.17k
                memcpy (new_sortbuf, sortbuf,
300
1.17k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.17k
                if (sortbuf != sortbuf_preallocated)
302
1.17k
                  free (sortbuf);
303
1.17k
                sortbuf = new_sortbuf;
304
1.17k
              }
305
20.9M
            sortbuf[sortbuf_count].code = uc;
306
20.9M
            sortbuf[sortbuf_count].ccc = ccc;
307
20.9M
            sortbuf_count++;
308
309
20.9M
            i++;
310
20.9M
          }
311
312
18.1M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
3.75M
          break;
315
316
14.4M
        s += count;
317
14.4M
      }
318
3.75M
  }
319
320
3.75M
  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.75M
  else if (result != resultbuf && length < allocated)
334
3.75M
    {
335
      /* Shrink the allocated memory if possible.  */
336
3.75M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
3.75M
      if (memory != NULL)
338
3.75M
        result = memory;
339
3.75M
    }
340
341
3.75M
  if (sortbuf_count > 0)
342
0
    abort ();
343
3.75M
  if (sortbuf != sortbuf_preallocated)
344
3.75M
    free (sortbuf);
345
346
3.75M
  *lengthp = length;
347
3.75M
  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.75M
}
u32_normalize
Line
Count
Source
21
7.56M
{
22
7.56M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
7.56M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
7.56M
  UNIT *result;
27
7.56M
  size_t allocated;
28
7.56M
  if (resultbuf == NULL)
29
7.56M
    {
30
7.56M
      result = NULL;
31
7.56M
      allocated = 0;
32
7.56M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
7.56M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
7.56M
  #define SORTBUF_PREALLOCATED 64
42
7.56M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
7.56M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
7.56M
    sortbuf_preallocated;
45
7.56M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
7.56M
  size_t sortbuf_count = 0;
47
48
7.56M
  {
49
7.56M
    const UNIT *s_end = s + n;
50
51
7.56M
    for (;;)
52
18.3M
      {
53
18.3M
        int count;
54
18.3M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
18.3M
        int decomposed_count;
56
57
18.3M
        if (s < s_end)
58
10.7M
          {
59
            /* Fetch the next character.  */
60
10.7M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
10.7M
            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
21.6M
            for (int curr = 0; curr < decomposed_count; )
70
10.8M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
10.8M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
10.8M
                int curr_decomposed_count;
75
76
10.8M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
10.8M
                if (curr_decomposed_count >= 0)
78
31.0k
                  {
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.0k
                    int shift = curr_decomposed_count - 1;
83
84
31.0k
                    if (shift < 0)
85
0
                      abort ();
86
31.0k
                    if (shift > 0)
87
30.8k
                      {
88
30.8k
                        decomposed_count += shift;
89
30.8k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
40.3k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
9.55k
                          decomposed[j + shift] = decomposed[j];
93
30.8k
                      }
94
92.8k
                    for (; shift >= 0; shift--)
95
61.8k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
31.0k
                  }
97
10.8M
                else
98
10.8M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
10.8M
                    curr++;
101
10.8M
                  }
102
10.8M
              }
103
10.7M
          }
104
7.56M
        else
105
7.56M
          {
106
7.56M
            count = 0;
107
7.56M
            decomposed_count = 0;
108
7.56M
          }
109
110
18.3M
        int i = 0;
111
18.3M
        for (;;)
112
29.1M
          {
113
29.1M
            ucs4_t uc;
114
29.1M
            int ccc;
115
116
29.1M
            if (s < s_end)
117
21.6M
              {
118
                /* Fetch the next character from the decomposition.  */
119
21.6M
                if (i == decomposed_count)
120
10.7M
                  break;
121
10.8M
                uc = decomposed[i];
122
10.8M
                ccc = uc_combining_class (uc);
123
10.8M
              }
124
7.56M
            else
125
7.56M
              {
126
                /* End of string reached.  */
127
7.56M
                uc = 0;
128
7.56M
                ccc = 0;
129
7.56M
              }
130
131
18.3M
            if (ccc == 0)
132
18.2M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
18.2M
                if (sortbuf_count > 1)
136
22.6k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
22.6k
                                                           sortbuf + sortbuf_count);
138
139
18.2M
                if (composer != NULL)
140
18.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
18.2M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
10.7M
                      {
163
10.8M
                        for (size_t j = 1; j < sortbuf_count; )
164
95.6k
                          {
165
95.6k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
32.8k
                              {
167
32.8k
                                ucs4_t combined =
168
32.8k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
32.8k
                                if (combined)
170
19.8k
                                  {
171
19.8k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
33.4k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
13.5k
                                      sortbuf[k - 1] = sortbuf[k];
175
19.8k
                                    sortbuf_count--;
176
19.8k
                                    continue;
177
19.8k
                                  }
178
32.8k
                              }
179
75.7k
                            j++;
180
75.7k
                          }
181
10.7M
                        if (s < s_end && sortbuf_count == 1)
182
3.20M
                          {
183
3.20M
                            ucs4_t combined =
184
3.20M
                              composer (sortbuf[0].code, uc);
185
3.20M
                            if (combined)
186
9.19k
                              {
187
9.19k
                                uc = combined;
188
9.19k
                                ccc = 0;
189
                                /* uc could be further combined with subsequent
190
                                   characters.  So don't put it into sortbuf[0] in
191
                                   this round, only in the next round.  */
192
9.19k
                                sortbuf_count = 0;
193
9.19k
                              }
194
3.20M
                          }
195
10.7M
                      }
196
18.2M
                  }
197
198
29.0M
                for (size_t j = 0; j < sortbuf_count; j++)
199
10.7M
                  {
200
10.7M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
10.7M
                    if (length < allocated)
204
3.28M
                      {
205
3.28M
                        int ret =
206
3.28M
                          U_UCTOMB (result + length, muc, allocated - length);
207
3.28M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
3.28M
                        if (ret >= 0)
213
3.28M
                          {
214
3.28M
                            length += ret;
215
3.28M
                            goto done_appending;
216
3.28M
                          }
217
3.28M
                      }
218
7.50M
                    {
219
7.50M
                      size_t old_allocated = allocated;
220
7.50M
                      size_t new_allocated = 2 * old_allocated;
221
7.50M
                      if (new_allocated < 64)
222
7.50M
                        new_allocated = 64;
223
7.50M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
7.50M
                      {
226
7.50M
                        UNIT *larger_result;
227
7.50M
                        if (result == NULL)
228
7.50M
                          {
229
7.50M
                            larger_result =
230
7.50M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
7.50M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
7.50M
                          }
237
2.79k
                        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
2.79k
                        else
249
2.79k
                          {
250
2.79k
                            larger_result =
251
2.79k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
2.79k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
2.79k
                          }
258
7.50M
                        result = larger_result;
259
7.50M
                        allocated = new_allocated;
260
7.50M
                        {
261
7.50M
                          int ret =
262
7.50M
                            U_UCTOMB (result + length, muc, allocated - length);
263
7.50M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
7.50M
                          if (ret < 0)
269
0
                            abort ();
270
7.50M
                          length += ret;
271
7.50M
                          goto done_appending;
272
7.50M
                        }
273
7.50M
                      }
274
7.50M
                    }
275
10.7M
                   done_appending: ;
276
10.7M
                  }
277
278
                /* sortbuf is now empty.  */
279
18.2M
                sortbuf_count = 0;
280
18.2M
              }
281
282
18.3M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
7.56M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
10.8M
            if (sortbuf_count == sortbuf_allocated)
288
816
              {
289
816
                sortbuf_allocated = 2 * sortbuf_allocated;
290
816
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
816
                struct ucs4_with_ccc *new_sortbuf =
293
816
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
816
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
816
                memcpy (new_sortbuf, sortbuf,
300
816
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
816
                if (sortbuf != sortbuf_preallocated)
302
816
                  free (sortbuf);
303
816
                sortbuf = new_sortbuf;
304
816
              }
305
10.8M
            sortbuf[sortbuf_count].code = uc;
306
10.8M
            sortbuf[sortbuf_count].ccc = ccc;
307
10.8M
            sortbuf_count++;
308
309
10.8M
            i++;
310
10.8M
          }
311
312
18.3M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
7.56M
          break;
315
316
10.7M
        s += count;
317
10.7M
      }
318
7.56M
  }
319
320
7.56M
  if (length == 0)
321
61.5k
    {
322
61.5k
      if (result == NULL)
323
61.5k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
61.5k
          result = (UNIT *) malloc (1);
326
61.5k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
61.5k
        }
332
61.5k
    }
333
7.50M
  else if (result != resultbuf && length < allocated)
334
7.49M
    {
335
      /* Shrink the allocated memory if possible.  */
336
7.49M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
7.49M
      if (memory != NULL)
338
7.49M
        result = memory;
339
7.49M
    }
340
341
7.56M
  if (sortbuf_count > 0)
342
0
    abort ();
343
7.56M
  if (sortbuf != sortbuf_preallocated)
344
7.56M
    free (sortbuf);
345
346
7.56M
  *lengthp = length;
347
7.56M
  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
7.56M
}