Coverage Report

Created: 2026-10-13 06:37

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.0M
{
22
11.0M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
11.0M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
11.0M
  UNIT *result;
27
11.0M
  size_t allocated;
28
11.0M
  if (resultbuf == NULL)
29
11.0M
    {
30
11.0M
      result = NULL;
31
11.0M
      allocated = 0;
32
11.0M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
11.0M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
11.0M
  #define SORTBUF_PREALLOCATED 64
42
11.0M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
11.0M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
11.0M
    sortbuf_preallocated;
45
11.0M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
11.0M
  size_t sortbuf_count = 0;
47
48
11.0M
  {
49
11.0M
    const UNIT *s_end = s + n;
50
51
11.0M
    for (;;)
52
36.1M
      {
53
36.1M
        int count;
54
36.1M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
36.1M
        int decomposed_count;
56
57
36.1M
        if (s < s_end)
58
25.1M
          {
59
            /* Fetch the next character.  */
60
25.1M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
25.1M
            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
59.8M
            for (int curr = 0; curr < decomposed_count; )
70
34.7M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
34.7M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
34.7M
                int curr_decomposed_count;
75
76
34.7M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
34.7M
                if (curr_decomposed_count >= 0)
78
3.32M
                  {
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.32M
                    int shift = curr_decomposed_count - 1;
83
84
3.32M
                    if (shift < 0)
85
0
                      abort ();
86
3.32M
                    if (shift > 0)
87
2.91M
                      {
88
2.91M
                        decomposed_count += shift;
89
2.91M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.93M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
27.3k
                          decomposed[j + shift] = decomposed[j];
93
2.91M
                      }
94
12.9M
                    for (; shift >= 0; shift--)
95
9.66M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.32M
                  }
97
31.4M
                else
98
31.4M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
31.4M
                    curr++;
101
31.4M
                  }
102
34.7M
              }
103
25.1M
          }
104
11.0M
        else
105
11.0M
          {
106
11.0M
            count = 0;
107
11.0M
            decomposed_count = 0;
108
11.0M
          }
109
110
36.1M
        int i = 0;
111
36.1M
        for (;;)
112
67.6M
          {
113
67.6M
            ucs4_t uc;
114
67.6M
            int ccc;
115
116
67.6M
            if (s < s_end)
117
56.5M
              {
118
                /* Fetch the next character from the decomposition.  */
119
56.5M
                if (i == decomposed_count)
120
25.1M
                  break;
121
31.4M
                uc = decomposed[i];
122
31.4M
                ccc = uc_combining_class (uc);
123
31.4M
              }
124
11.0M
            else
125
11.0M
              {
126
                /* End of string reached.  */
127
11.0M
                uc = 0;
128
11.0M
                ccc = 0;
129
11.0M
              }
130
131
42.5M
            if (ccc == 0)
132
39.1M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
39.1M
                if (sortbuf_count > 1)
136
1.75M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.75M
                                                           sortbuf + sortbuf_count);
138
139
39.1M
                if (composer != NULL)
140
39.1M
                  {
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.1M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
28.1M
                      {
163
31.4M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.28M
                          {
165
3.28M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.79M
                              {
167
1.79M
                                ucs4_t combined =
168
1.79M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.79M
                                if (combined)
170
1.72M
                                  {
171
1.72M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.60M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
1.87M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.72M
                                    sortbuf_count--;
176
1.72M
                                    continue;
177
1.72M
                                  }
178
1.79M
                              }
179
1.56M
                            j++;
180
1.56M
                          }
181
28.1M
                        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
16.6k
                              {
187
16.6k
                                uc = combined;
188
16.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
16.6k
                                sortbuf_count = 0;
193
16.6k
                              }
194
17.1M
                          }
195
28.1M
                      }
196
39.1M
                  }
197
198
68.8M
                for (size_t j = 0; j < sortbuf_count; j++)
199
29.7M
                  {
200
29.7M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
29.7M
                    if (length < allocated)
204
18.7M
                      {
205
18.7M
                        int ret =
206
18.7M
                          U_UCTOMB (result + length, muc, allocated - length);
207
18.7M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
18.7M
                        if (ret >= 0)
213
18.7M
                          {
214
18.7M
                            length += ret;
215
18.7M
                            goto done_appending;
216
18.7M
                          }
217
18.7M
                      }
218
10.9M
                    {
219
10.9M
                      size_t old_allocated = allocated;
220
10.9M
                      size_t new_allocated = 2 * old_allocated;
221
10.9M
                      if (new_allocated < 64)
222
10.9M
                        new_allocated = 64;
223
10.9M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
10.9M
                      {
226
10.9M
                        UNIT *larger_result;
227
10.9M
                        if (result == NULL)
228
10.9M
                          {
229
10.9M
                            larger_result =
230
10.9M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
10.9M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
10.9M
                          }
237
15.4k
                        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.4k
                        else
249
15.4k
                          {
250
15.4k
                            larger_result =
251
15.4k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
15.4k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
15.4k
                          }
258
10.9M
                        result = larger_result;
259
10.9M
                        allocated = new_allocated;
260
10.9M
                        {
261
10.9M
                          int ret =
262
10.9M
                            U_UCTOMB (result + length, muc, allocated - length);
263
10.9M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
10.9M
                          if (ret < 0)
269
0
                            abort ();
270
10.9M
                          length += ret;
271
10.9M
                          goto done_appending;
272
10.9M
                        }
273
10.9M
                      }
274
10.9M
                    }
275
29.7M
                   done_appending: ;
276
29.7M
                  }
277
278
                /* sortbuf is now empty.  */
279
39.1M
                sortbuf_count = 0;
280
39.1M
              }
281
282
42.5M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
11.0M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
31.4M
            if (sortbuf_count == sortbuf_allocated)
288
2.10k
              {
289
2.10k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
2.10k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
2.10k
                struct ucs4_with_ccc *new_sortbuf =
293
2.10k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
2.10k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
2.10k
                memcpy (new_sortbuf, sortbuf,
300
2.10k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
2.10k
                if (sortbuf != sortbuf_preallocated)
302
2.10k
                  free (sortbuf);
303
2.10k
                sortbuf = new_sortbuf;
304
2.10k
              }
305
31.4M
            sortbuf[sortbuf_count].code = uc;
306
31.4M
            sortbuf[sortbuf_count].ccc = ccc;
307
31.4M
            sortbuf_count++;
308
309
31.4M
            i++;
310
31.4M
          }
311
312
36.1M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
11.0M
          break;
315
316
25.1M
        s += count;
317
25.1M
      }
318
11.0M
  }
319
320
11.0M
  if (length == 0)
321
96.0k
    {
322
96.0k
      if (result == NULL)
323
96.0k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
96.0k
          result = (UNIT *) malloc (1);
326
96.0k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
96.0k
        }
332
96.0k
    }
333
10.9M
  else if (result != resultbuf && length < allocated)
334
10.9M
    {
335
      /* Shrink the allocated memory if possible.  */
336
10.9M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
10.9M
      if (memory != NULL)
338
10.9M
        result = memory;
339
10.9M
    }
340
341
11.0M
  if (sortbuf_count > 0)
342
0
    abort ();
343
11.0M
  if (sortbuf != sortbuf_preallocated)
344
11.0M
    free (sortbuf);
345
346
11.0M
  *lengthp = length;
347
11.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
11.0M
}
u8_normalize
Line
Count
Source
21
3.58M
{
22
3.58M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
3.58M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
3.58M
  UNIT *result;
27
3.58M
  size_t allocated;
28
3.58M
  if (resultbuf == NULL)
29
3.58M
    {
30
3.58M
      result = NULL;
31
3.58M
      allocated = 0;
32
3.58M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
3.58M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
3.58M
  #define SORTBUF_PREALLOCATED 64
42
3.58M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
3.58M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
3.58M
    sortbuf_preallocated;
45
3.58M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
3.58M
  size_t sortbuf_count = 0;
47
48
3.58M
  {
49
3.58M
    const UNIT *s_end = s + n;
50
51
3.58M
    for (;;)
52
17.8M
      {
53
17.8M
        int count;
54
17.8M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
17.8M
        int decomposed_count;
56
57
17.8M
        if (s < s_end)
58
14.2M
          {
59
            /* Fetch the next character.  */
60
14.2M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
14.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
38.1M
            for (int curr = 0; curr < decomposed_count; )
70
23.8M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
23.8M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
23.8M
                int curr_decomposed_count;
75
76
23.8M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
23.8M
                if (curr_decomposed_count >= 0)
78
3.29M
                  {
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.29M
                    int shift = curr_decomposed_count - 1;
83
84
3.29M
                    if (shift < 0)
85
0
                      abort ();
86
3.29M
                    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.89M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
17.1k
                          decomposed[j + shift] = decomposed[j];
93
2.87M
                      }
94
12.8M
                    for (; shift >= 0; shift--)
95
9.60M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.29M
                  }
97
20.5M
                else
98
20.5M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
20.5M
                    curr++;
101
20.5M
                  }
102
23.8M
              }
103
14.2M
          }
104
3.58M
        else
105
3.58M
          {
106
3.58M
            count = 0;
107
3.58M
            decomposed_count = 0;
108
3.58M
          }
109
110
17.8M
        int i = 0;
111
17.8M
        for (;;)
112
38.4M
          {
113
38.4M
            ucs4_t uc;
114
38.4M
            int ccc;
115
116
38.4M
            if (s < s_end)
117
34.8M
              {
118
                /* Fetch the next character from the decomposition.  */
119
34.8M
                if (i == decomposed_count)
120
14.2M
                  break;
121
20.5M
                uc = decomposed[i];
122
20.5M
                ccc = uc_combining_class (uc);
123
20.5M
              }
124
3.58M
            else
125
3.58M
              {
126
                /* End of string reached.  */
127
3.58M
                uc = 0;
128
3.58M
                ccc = 0;
129
3.58M
              }
130
131
24.1M
            if (ccc == 0)
132
20.9M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
20.9M
                if (sortbuf_count > 1)
136
1.72M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.72M
                                                           sortbuf + sortbuf_count);
138
139
20.9M
                if (composer != NULL)
140
20.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
20.9M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
17.3M
                      {
163
20.5M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.18M
                          {
165
3.18M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.75M
                              {
167
1.75M
                                ucs4_t combined =
168
1.75M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.75M
                                if (combined)
170
1.70M
                                  {
171
1.70M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.56M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
1.85M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.70M
                                    sortbuf_count--;
176
1.70M
                                    continue;
177
1.70M
                                  }
178
1.75M
                              }
179
1.47M
                            j++;
180
1.47M
                          }
181
17.3M
                        if (s < s_end && sortbuf_count == 1)
182
13.7M
                          {
183
13.7M
                            ucs4_t combined =
184
13.7M
                              composer (sortbuf[0].code, uc);
185
13.7M
                            if (combined)
186
7.66k
                              {
187
7.66k
                                uc = combined;
188
7.66k
                                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
7.66k
                                sortbuf_count = 0;
193
7.66k
                              }
194
13.7M
                          }
195
17.3M
                      }
196
20.9M
                  }
197
198
39.8M
                for (size_t j = 0; j < sortbuf_count; j++)
199
18.8M
                  {
200
18.8M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
18.8M
                    if (length < allocated)
204
15.2M
                      {
205
15.2M
                        int ret =
206
15.2M
                          U_UCTOMB (result + length, muc, allocated - length);
207
15.2M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
15.2M
                        if (ret >= 0)
213
15.2M
                          {
214
15.2M
                            length += ret;
215
15.2M
                            goto done_appending;
216
15.2M
                          }
217
15.2M
                      }
218
3.59M
                    {
219
3.59M
                      size_t old_allocated = allocated;
220
3.59M
                      size_t new_allocated = 2 * old_allocated;
221
3.59M
                      if (new_allocated < 64)
222
3.58M
                        new_allocated = 64;
223
3.59M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
3.59M
                      {
226
3.59M
                        UNIT *larger_result;
227
3.59M
                        if (result == NULL)
228
3.58M
                          {
229
3.58M
                            larger_result =
230
3.58M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
3.58M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
3.58M
                          }
237
12.6k
                        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.6k
                        else
249
12.6k
                          {
250
12.6k
                            larger_result =
251
12.6k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
12.6k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
12.6k
                          }
258
3.59M
                        result = larger_result;
259
3.59M
                        allocated = new_allocated;
260
3.59M
                        {
261
3.59M
                          int ret =
262
3.59M
                            U_UCTOMB (result + length, muc, allocated - length);
263
3.59M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
3.59M
                          if (ret < 0)
269
0
                            abort ();
270
3.59M
                          length += ret;
271
3.59M
                          goto done_appending;
272
3.59M
                        }
273
3.59M
                      }
274
3.59M
                    }
275
18.8M
                   done_appending: ;
276
18.8M
                  }
277
278
                /* sortbuf is now empty.  */
279
20.9M
                sortbuf_count = 0;
280
20.9M
              }
281
282
24.1M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
3.58M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
20.5M
            if (sortbuf_count == sortbuf_allocated)
288
1.21k
              {
289
1.21k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.21k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.21k
                struct ucs4_with_ccc *new_sortbuf =
293
1.21k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.21k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.21k
                memcpy (new_sortbuf, sortbuf,
300
1.21k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.21k
                if (sortbuf != sortbuf_preallocated)
302
1.21k
                  free (sortbuf);
303
1.21k
                sortbuf = new_sortbuf;
304
1.21k
              }
305
20.5M
            sortbuf[sortbuf_count].code = uc;
306
20.5M
            sortbuf[sortbuf_count].ccc = ccc;
307
20.5M
            sortbuf_count++;
308
309
20.5M
            i++;
310
20.5M
          }
311
312
17.8M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
3.58M
          break;
315
316
14.2M
        s += count;
317
14.2M
      }
318
3.58M
  }
319
320
3.58M
  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.58M
  else if (result != resultbuf && length < allocated)
334
3.58M
    {
335
      /* Shrink the allocated memory if possible.  */
336
3.58M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
3.58M
      if (memory != NULL)
338
3.58M
        result = memory;
339
3.58M
    }
340
341
3.58M
  if (sortbuf_count > 0)
342
0
    abort ();
343
3.58M
  if (sortbuf != sortbuf_preallocated)
344
3.58M
    free (sortbuf);
345
346
3.58M
  *lengthp = length;
347
3.58M
  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.58M
}
u32_normalize
Line
Count
Source
21
7.48M
{
22
7.48M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
7.48M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
7.48M
  UNIT *result;
27
7.48M
  size_t allocated;
28
7.48M
  if (resultbuf == NULL)
29
7.48M
    {
30
7.48M
      result = NULL;
31
7.48M
      allocated = 0;
32
7.48M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
7.48M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
7.48M
  #define SORTBUF_PREALLOCATED 64
42
7.48M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
7.48M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
7.48M
    sortbuf_preallocated;
45
7.48M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
7.48M
  size_t sortbuf_count = 0;
47
48
7.48M
  {
49
7.48M
    const UNIT *s_end = s + n;
50
51
7.48M
    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.8M
          {
59
            /* Fetch the next character.  */
60
10.8M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
10.8M
            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.7M
            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
33.5k
                  {
79
                    /* Move curr_decomposed[0..curr_decomposed_count-1] over
80
                       decomposed[curr], making room.  It's not worth using
81
                       memcpy() here, since the counts are so small.  */
82
33.5k
                    int shift = curr_decomposed_count - 1;
83
84
33.5k
                    if (shift < 0)
85
0
                      abort ();
86
33.5k
                    if (shift > 0)
87
33.3k
                      {
88
33.3k
                        decomposed_count += shift;
89
33.3k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
43.5k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
10.2k
                          decomposed[j + shift] = decomposed[j];
93
33.3k
                      }
94
100k
                    for (; shift >= 0; shift--)
95
66.8k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
33.5k
                  }
97
10.8M
                else
98
10.8M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
10.8M
                    curr++;
101
10.8M
                  }
102
10.8M
              }
103
10.8M
          }
104
7.48M
        else
105
7.48M
          {
106
7.48M
            count = 0;
107
7.48M
            decomposed_count = 0;
108
7.48M
          }
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.8M
                  break;
121
10.8M
                uc = decomposed[i];
122
10.8M
                ccc = uc_combining_class (uc);
123
10.8M
              }
124
7.48M
            else
125
7.48M
              {
126
                /* End of string reached.  */
127
7.48M
                uc = 0;
128
7.48M
                ccc = 0;
129
7.48M
              }
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
25.7k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
25.7k
                                                           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
108k
                          {
165
108k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
37.3k
                              {
167
37.3k
                                ucs4_t combined =
168
37.3k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
37.3k
                                if (combined)
170
22.5k
                                  {
171
22.5k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
37.1k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
14.5k
                                      sortbuf[k - 1] = sortbuf[k];
175
22.5k
                                    sortbuf_count--;
176
22.5k
                                    continue;
177
22.5k
                                  }
178
37.3k
                              }
179
85.8k
                            j++;
180
85.8k
                          }
181
10.7M
                        if (s < s_end && sortbuf_count == 1)
182
3.34M
                          {
183
3.34M
                            ucs4_t combined =
184
3.34M
                              composer (sortbuf[0].code, uc);
185
3.34M
                            if (combined)
186
8.98k
                              {
187
8.98k
                                uc = combined;
188
8.98k
                                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.98k
                                sortbuf_count = 0;
193
8.98k
                              }
194
3.34M
                          }
195
10.7M
                      }
196
18.2M
                  }
197
198
29.0M
                for (size_t j = 0; j < sortbuf_count; j++)
199
10.8M
                  {
200
10.8M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
10.8M
                    if (length < allocated)
204
3.43M
                      {
205
3.43M
                        int ret =
206
3.43M
                          U_UCTOMB (result + length, muc, allocated - length);
207
3.43M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
3.43M
                        if (ret >= 0)
213
3.43M
                          {
214
3.43M
                            length += ret;
215
3.43M
                            goto done_appending;
216
3.43M
                          }
217
3.43M
                      }
218
7.39M
                    {
219
7.39M
                      size_t old_allocated = allocated;
220
7.39M
                      size_t new_allocated = 2 * old_allocated;
221
7.39M
                      if (new_allocated < 64)
222
7.39M
                        new_allocated = 64;
223
7.39M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
7.39M
                      {
226
7.39M
                        UNIT *larger_result;
227
7.39M
                        if (result == NULL)
228
7.39M
                          {
229
7.39M
                            larger_result =
230
7.39M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
7.39M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
7.39M
                          }
237
2.77k
                        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.77k
                        else
249
2.77k
                          {
250
2.77k
                            larger_result =
251
2.77k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
2.77k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
2.77k
                          }
258
7.39M
                        result = larger_result;
259
7.39M
                        allocated = new_allocated;
260
7.39M
                        {
261
7.39M
                          int ret =
262
7.39M
                            U_UCTOMB (result + length, muc, allocated - length);
263
7.39M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
7.39M
                          if (ret < 0)
269
0
                            abort ();
270
7.39M
                          length += ret;
271
7.39M
                          goto done_appending;
272
7.39M
                        }
273
7.39M
                      }
274
7.39M
                    }
275
10.8M
                   done_appending: ;
276
10.8M
                  }
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.48M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
10.8M
            if (sortbuf_count == sortbuf_allocated)
288
895
              {
289
895
                sortbuf_allocated = 2 * sortbuf_allocated;
290
895
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
895
                struct ucs4_with_ccc *new_sortbuf =
293
895
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
895
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
895
                memcpy (new_sortbuf, sortbuf,
300
895
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
895
                if (sortbuf != sortbuf_preallocated)
302
895
                  free (sortbuf);
303
895
                sortbuf = new_sortbuf;
304
895
              }
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.48M
          break;
315
316
10.8M
        s += count;
317
10.8M
      }
318
7.48M
  }
319
320
7.48M
  if (length == 0)
321
96.0k
    {
322
96.0k
      if (result == NULL)
323
96.0k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
96.0k
          result = (UNIT *) malloc (1);
326
96.0k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
96.0k
        }
332
96.0k
    }
333
7.39M
  else if (result != resultbuf && length < allocated)
334
7.39M
    {
335
      /* Shrink the allocated memory if possible.  */
336
7.39M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
7.39M
      if (memory != NULL)
338
7.39M
        result = memory;
339
7.39M
    }
340
341
7.48M
  if (sortbuf_count > 0)
342
0
    abort ();
343
7.48M
  if (sortbuf != sortbuf_preallocated)
344
7.48M
    free (sortbuf);
345
346
7.48M
  *lengthp = length;
347
7.48M
  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.48M
}