Coverage Report

Created: 2026-08-12 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libunistring/lib/uninorm/u-normalize-internal.h
Line
Count
Source
1
/* Decomposition and composition of Unicode strings.
2
   Copyright (C) 2009-2026 Free Software Foundation, Inc.
3
   Written by Bruno Haible <bruno@clisp.org>, 2009.
4
5
   This file is free software: you can redistribute it and/or modify
6
   it under the terms of the GNU Lesser General Public License as
7
   published by the Free Software Foundation; either version 2.1 of the
8
   License, or (at your option) any later version.
9
10
   This file is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU Lesser General Public License for more details.
14
15
   You should have received a copy of the GNU Lesser General Public License
16
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17
18
UNIT *
19
FUNC (uninorm_t nf, const UNIT *s, size_t n,
20
      UNIT *resultbuf, size_t *lengthp)
21
10.3M
{
22
10.3M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
10.3M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
10.3M
  UNIT *result;
27
10.3M
  size_t allocated;
28
10.3M
  if (resultbuf == NULL)
29
10.3M
    {
30
10.3M
      result = NULL;
31
10.3M
      allocated = 0;
32
10.3M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
10.3M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
10.3M
  #define SORTBUF_PREALLOCATED 64
42
10.3M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
10.3M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
10.3M
    sortbuf_preallocated;
45
10.3M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
10.3M
  size_t sortbuf_count = 0;
47
48
10.3M
  {
49
10.3M
    const UNIT *s_end = s + n;
50
51
10.3M
    for (;;)
52
33.9M
      {
53
33.9M
        int count;
54
33.9M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
33.9M
        int decomposed_count;
56
57
33.9M
        if (s < s_end)
58
23.6M
          {
59
            /* Fetch the next character.  */
60
23.6M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
23.6M
            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
57.3M
            for (int curr = 0; curr < decomposed_count; )
70
33.6M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
33.6M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
33.6M
                int curr_decomposed_count;
75
76
33.6M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
33.6M
                if (curr_decomposed_count >= 0)
78
3.24M
                  {
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.24M
                    int shift = curr_decomposed_count - 1;
83
84
3.24M
                    if (shift < 0)
85
0
                      abort ();
86
3.24M
                    if (shift > 0)
87
2.88M
                      {
88
2.88M
                        decomposed_count += shift;
89
2.88M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.91M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
26.0k
                          decomposed[j + shift] = decomposed[j];
93
2.88M
                      }
94
13.2M
                    for (; shift >= 0; shift--)
95
9.96M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.24M
                  }
97
30.3M
                else
98
30.3M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
30.3M
                    curr++;
101
30.3M
                  }
102
33.6M
              }
103
23.6M
          }
104
10.3M
        else
105
10.3M
          {
106
10.3M
            count = 0;
107
10.3M
            decomposed_count = 0;
108
10.3M
          }
109
110
33.9M
        int i = 0;
111
33.9M
        for (;;)
112
64.3M
          {
113
64.3M
            ucs4_t uc;
114
64.3M
            int ccc;
115
116
64.3M
            if (s < s_end)
117
54.0M
              {
118
                /* Fetch the next character from the decomposition.  */
119
54.0M
                if (i == decomposed_count)
120
23.6M
                  break;
121
30.3M
                uc = decomposed[i];
122
30.3M
                ccc = uc_combining_class (uc);
123
30.3M
              }
124
10.3M
            else
125
10.3M
              {
126
                /* End of string reached.  */
127
10.3M
                uc = 0;
128
10.3M
                ccc = 0;
129
10.3M
              }
130
131
40.7M
            if (ccc == 0)
132
37.4M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
37.4M
                if (sortbuf_count > 1)
136
1.68M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.68M
                                                           sortbuf + sortbuf_count);
138
139
37.4M
                if (composer != NULL)
140
37.4M
                  {
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
37.4M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
27.1M
                      {
163
30.3M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.24M
                          {
165
3.24M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.72M
                              {
167
1.72M
                                ucs4_t combined =
168
1.72M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.72M
                                if (combined)
170
1.66M
                                  {
171
1.66M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.74M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.07M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.66M
                                    sortbuf_count--;
176
1.66M
                                    continue;
177
1.66M
                                  }
178
1.72M
                              }
179
1.57M
                            j++;
180
1.57M
                          }
181
27.1M
                        if (s < s_end && sortbuf_count == 1)
182
16.8M
                          {
183
16.8M
                            ucs4_t combined =
184
16.8M
                              composer (sortbuf[0].code, uc);
185
16.8M
                            if (combined)
186
16.2k
                              {
187
16.2k
                                uc = combined;
188
16.2k
                                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.2k
                                sortbuf_count = 0;
193
16.2k
                              }
194
16.8M
                          }
195
27.1M
                      }
196
37.4M
                  }
197
198
66.1M
                for (size_t j = 0; j < sortbuf_count; j++)
199
28.7M
                  {
200
28.7M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
28.7M
                    if (length < allocated)
204
18.4M
                      {
205
18.4M
                        int ret =
206
18.4M
                          U_UCTOMB (result + length, muc, allocated - length);
207
18.4M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
18.4M
                        if (ret >= 0)
213
18.4M
                          {
214
18.4M
                            length += ret;
215
18.4M
                            goto done_appending;
216
18.4M
                          }
217
18.4M
                      }
218
10.2M
                    {
219
10.2M
                      size_t old_allocated = allocated;
220
10.2M
                      size_t new_allocated = 2 * old_allocated;
221
10.2M
                      if (new_allocated < 64)
222
10.2M
                        new_allocated = 64;
223
10.2M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
10.2M
                      {
226
10.2M
                        UNIT *larger_result;
227
10.2M
                        if (result == NULL)
228
10.2M
                          {
229
10.2M
                            larger_result =
230
10.2M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
10.2M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
10.2M
                          }
237
15.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
15.5k
                        else
249
15.5k
                          {
250
15.5k
                            larger_result =
251
15.5k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
15.5k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
15.5k
                          }
258
10.2M
                        result = larger_result;
259
10.2M
                        allocated = new_allocated;
260
10.2M
                        {
261
10.2M
                          int ret =
262
10.2M
                            U_UCTOMB (result + length, muc, allocated - length);
263
10.2M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
10.2M
                          if (ret < 0)
269
0
                            abort ();
270
10.2M
                          length += ret;
271
10.2M
                          goto done_appending;
272
10.2M
                        }
273
10.2M
                      }
274
10.2M
                    }
275
28.7M
                   done_appending: ;
276
28.7M
                  }
277
278
                /* sortbuf is now empty.  */
279
37.4M
                sortbuf_count = 0;
280
37.4M
              }
281
282
40.7M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
10.3M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
30.3M
            if (sortbuf_count == sortbuf_allocated)
288
1.94k
              {
289
1.94k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.94k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.94k
                struct ucs4_with_ccc *new_sortbuf =
293
1.94k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.94k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.94k
                memcpy (new_sortbuf, sortbuf,
300
1.94k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.94k
                if (sortbuf != sortbuf_preallocated)
302
1.94k
                  free (sortbuf);
303
1.94k
                sortbuf = new_sortbuf;
304
1.94k
              }
305
30.3M
            sortbuf[sortbuf_count].code = uc;
306
30.3M
            sortbuf[sortbuf_count].ccc = ccc;
307
30.3M
            sortbuf_count++;
308
309
30.3M
            i++;
310
30.3M
          }
311
312
33.9M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
10.3M
          break;
315
316
23.6M
        s += count;
317
23.6M
      }
318
10.3M
  }
319
320
10.3M
  if (length == 0)
321
60.8k
    {
322
60.8k
      if (result == NULL)
323
60.8k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
60.8k
          result = (UNIT *) malloc (1);
326
60.8k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
60.8k
        }
332
60.8k
    }
333
10.2M
  else if (result != resultbuf && length < allocated)
334
10.2M
    {
335
      /* Shrink the allocated memory if possible.  */
336
10.2M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
10.2M
      if (memory != NULL)
338
10.2M
        result = memory;
339
10.2M
    }
340
341
10.3M
  if (sortbuf_count > 0)
342
0
    abort ();
343
10.3M
  if (sortbuf != sortbuf_preallocated)
344
10.3M
    free (sortbuf);
345
346
10.3M
  *lengthp = length;
347
10.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
10.3M
}
u8_normalize
Line
Count
Source
21
3.40M
{
22
3.40M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
3.40M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
3.40M
  UNIT *result;
27
3.40M
  size_t allocated;
28
3.40M
  if (resultbuf == NULL)
29
3.40M
    {
30
3.40M
      result = NULL;
31
3.40M
      allocated = 0;
32
3.40M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
3.40M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
3.40M
  #define SORTBUF_PREALLOCATED 64
42
3.40M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
3.40M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
3.40M
    sortbuf_preallocated;
45
3.40M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
3.40M
  size_t sortbuf_count = 0;
47
48
3.40M
  {
49
3.40M
    const UNIT *s_end = s + n;
50
51
3.40M
    for (;;)
52
17.0M
      {
53
17.0M
        int count;
54
17.0M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
17.0M
        int decomposed_count;
56
57
17.0M
        if (s < s_end)
58
13.6M
          {
59
            /* Fetch the next character.  */
60
13.6M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
13.6M
            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
37.2M
            for (int curr = 0; curr < decomposed_count; )
70
23.5M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
23.5M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
23.5M
                int curr_decomposed_count;
75
76
23.5M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
23.5M
                if (curr_decomposed_count >= 0)
78
3.21M
                  {
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.21M
                    int shift = curr_decomposed_count - 1;
83
84
3.21M
                    if (shift < 0)
85
0
                      abort ();
86
3.21M
                    if (shift > 0)
87
2.85M
                      {
88
2.85M
                        decomposed_count += shift;
89
2.85M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.87M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
16.9k
                          decomposed[j + shift] = decomposed[j];
93
2.85M
                      }
94
13.1M
                    for (; shift >= 0; shift--)
95
9.90M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.21M
                  }
97
20.3M
                else
98
20.3M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
20.3M
                    curr++;
101
20.3M
                  }
102
23.5M
              }
103
13.6M
          }
104
3.40M
        else
105
3.40M
          {
106
3.40M
            count = 0;
107
3.40M
            decomposed_count = 0;
108
3.40M
          }
109
110
17.0M
        int i = 0;
111
17.0M
        for (;;)
112
37.4M
          {
113
37.4M
            ucs4_t uc;
114
37.4M
            int ccc;
115
116
37.4M
            if (s < s_end)
117
34.0M
              {
118
                /* Fetch the next character from the decomposition.  */
119
34.0M
                if (i == decomposed_count)
120
13.6M
                  break;
121
20.3M
                uc = decomposed[i];
122
20.3M
                ccc = uc_combining_class (uc);
123
20.3M
              }
124
3.40M
            else
125
3.40M
              {
126
                /* End of string reached.  */
127
3.40M
                uc = 0;
128
3.40M
                ccc = 0;
129
3.40M
              }
130
131
23.7M
            if (ccc == 0)
132
20.5M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
20.5M
                if (sortbuf_count > 1)
136
1.66M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.66M
                                                           sortbuf + sortbuf_count);
138
139
20.5M
                if (composer != NULL)
140
20.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
20.5M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
17.1M
                      {
163
20.3M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.14M
                          {
165
3.14M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.68M
                              {
167
1.68M
                                ucs4_t combined =
168
1.68M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.68M
                                if (combined)
170
1.64M
                                  {
171
1.64M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.70M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.06M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.64M
                                    sortbuf_count--;
176
1.64M
                                    continue;
177
1.64M
                                  }
178
1.68M
                              }
179
1.49M
                            j++;
180
1.49M
                          }
181
17.1M
                        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.88k
                              {
187
7.88k
                                uc = combined;
188
7.88k
                                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.88k
                                sortbuf_count = 0;
193
7.88k
                              }
194
13.7M
                          }
195
17.1M
                      }
196
20.5M
                  }
197
198
39.2M
                for (size_t j = 0; j < sortbuf_count; j++)
199
18.7M
                  {
200
18.7M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
18.7M
                    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.41M
                    {
219
3.41M
                      size_t old_allocated = allocated;
220
3.41M
                      size_t new_allocated = 2 * old_allocated;
221
3.41M
                      if (new_allocated < 64)
222
3.40M
                        new_allocated = 64;
223
3.41M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
3.41M
                      {
226
3.41M
                        UNIT *larger_result;
227
3.41M
                        if (result == NULL)
228
3.40M
                          {
229
3.40M
                            larger_result =
230
3.40M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
3.40M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
3.40M
                          }
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.41M
                        result = larger_result;
259
3.41M
                        allocated = new_allocated;
260
3.41M
                        {
261
3.41M
                          int ret =
262
3.41M
                            U_UCTOMB (result + length, muc, allocated - length);
263
3.41M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
3.41M
                          if (ret < 0)
269
0
                            abort ();
270
3.41M
                          length += ret;
271
3.41M
                          goto done_appending;
272
3.41M
                        }
273
3.41M
                      }
274
3.41M
                    }
275
18.7M
                   done_appending: ;
276
18.7M
                  }
277
278
                /* sortbuf is now empty.  */
279
20.5M
                sortbuf_count = 0;
280
20.5M
              }
281
282
23.7M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
3.40M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
20.3M
            if (sortbuf_count == sortbuf_allocated)
288
1.14k
              {
289
1.14k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.14k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.14k
                struct ucs4_with_ccc *new_sortbuf =
293
1.14k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.14k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.14k
                memcpy (new_sortbuf, sortbuf,
300
1.14k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.14k
                if (sortbuf != sortbuf_preallocated)
302
1.14k
                  free (sortbuf);
303
1.14k
                sortbuf = new_sortbuf;
304
1.14k
              }
305
20.3M
            sortbuf[sortbuf_count].code = uc;
306
20.3M
            sortbuf[sortbuf_count].ccc = ccc;
307
20.3M
            sortbuf_count++;
308
309
20.3M
            i++;
310
20.3M
          }
311
312
17.0M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
3.40M
          break;
315
316
13.6M
        s += count;
317
13.6M
      }
318
3.40M
  }
319
320
3.40M
  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.40M
  else if (result != resultbuf && length < allocated)
334
3.40M
    {
335
      /* Shrink the allocated memory if possible.  */
336
3.40M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
3.40M
      if (memory != NULL)
338
3.40M
        result = memory;
339
3.40M
    }
340
341
3.40M
  if (sortbuf_count > 0)
342
0
    abort ();
343
3.40M
  if (sortbuf != sortbuf_preallocated)
344
3.40M
    free (sortbuf);
345
346
3.40M
  *lengthp = length;
347
3.40M
  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.40M
}
u32_normalize
Line
Count
Source
21
6.91M
{
22
6.91M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
6.91M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
6.91M
  UNIT *result;
27
6.91M
  size_t allocated;
28
6.91M
  if (resultbuf == NULL)
29
6.91M
    {
30
6.91M
      result = NULL;
31
6.91M
      allocated = 0;
32
6.91M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
6.91M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
6.91M
  #define SORTBUF_PREALLOCATED 64
42
6.91M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
6.91M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
6.91M
    sortbuf_preallocated;
45
6.91M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
6.91M
  size_t sortbuf_count = 0;
47
48
6.91M
  {
49
6.91M
    const UNIT *s_end = s + n;
50
51
6.91M
    for (;;)
52
16.9M
      {
53
16.9M
        int count;
54
16.9M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
16.9M
        int decomposed_count;
56
57
16.9M
        if (s < s_end)
58
9.99M
          {
59
            /* Fetch the next character.  */
60
9.99M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
9.99M
            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
20.0M
            for (int curr = 0; curr < decomposed_count; )
70
10.0M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
10.0M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
10.0M
                int curr_decomposed_count;
75
76
10.0M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
10.0M
                if (curr_decomposed_count >= 0)
78
30.8k
                  {
79
                    /* Move curr_decomposed[0..curr_decomposed_count-1] over
80
                       decomposed[curr], making room.  It's not worth using
81
                       memcpy() here, since the counts are so small.  */
82
30.8k
                    int shift = curr_decomposed_count - 1;
83
84
30.8k
                    if (shift < 0)
85
0
                      abort ();
86
30.8k
                    if (shift > 0)
87
30.5k
                      {
88
30.5k
                        decomposed_count += shift;
89
30.5k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
39.6k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
9.10k
                          decomposed[j + shift] = decomposed[j];
93
30.5k
                      }
94
92.2k
                    for (; shift >= 0; shift--)
95
61.4k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
30.8k
                  }
97
10.0M
                else
98
10.0M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
10.0M
                    curr++;
101
10.0M
                  }
102
10.0M
              }
103
9.99M
          }
104
6.91M
        else
105
6.91M
          {
106
6.91M
            count = 0;
107
6.91M
            decomposed_count = 0;
108
6.91M
          }
109
110
16.9M
        int i = 0;
111
16.9M
        for (;;)
112
26.9M
          {
113
26.9M
            ucs4_t uc;
114
26.9M
            int ccc;
115
116
26.9M
            if (s < s_end)
117
20.0M
              {
118
                /* Fetch the next character from the decomposition.  */
119
20.0M
                if (i == decomposed_count)
120
9.99M
                  break;
121
10.0M
                uc = decomposed[i];
122
10.0M
                ccc = uc_combining_class (uc);
123
10.0M
              }
124
6.91M
            else
125
6.91M
              {
126
                /* End of string reached.  */
127
6.91M
                uc = 0;
128
6.91M
                ccc = 0;
129
6.91M
              }
130
131
16.9M
            if (ccc == 0)
132
16.8M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
16.8M
                if (sortbuf_count > 1)
136
24.9k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
24.9k
                                                           sortbuf + sortbuf_count);
138
139
16.8M
                if (composer != NULL)
140
16.8M
                  {
141
                    /* Attempt to combine decomposed characters, as specified
142
                       in the Unicode Standard Annex #15 "Unicode Normalization
143
                       Forms".  We need to check
144
                         1. whether the first accumulated character is a
145
                            "starter" (i.e. has ccc = 0).  This is usually the
146
                            case.  But when the string starts with a
147
                            non-starter, the sortbuf also starts with a
148
                            non-starter.  Btw, this check could also be
149
                            omitted, because the composition table has only
150
                            entries (code1, code2) for which code1 is a
151
                            starter; if the first accumulated character is not
152
                            a starter, no lookup will succeed.
153
                         2. If the sortbuf has more than one character, check
154
                            for each of these characters that are not "blocked"
155
                            from the starter (i.e. have a ccc that is higher
156
                            than the ccc of the previous character) whether it
157
                            can be combined with the first character.
158
                         3. If only one character is left in sortbuf, check
159
                            whether it can be combined with the next character
160
                            (also a starter).  */
161
16.8M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
9.91M
                      {
163
10.0M
                        for (size_t j = 1; j < sortbuf_count; )
164
100k
                          {
165
100k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
35.1k
                              {
167
35.1k
                                ucs4_t combined =
168
35.1k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
35.1k
                                if (combined)
170
20.5k
                                  {
171
20.5k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
34.1k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
13.5k
                                      sortbuf[k - 1] = sortbuf[k];
175
20.5k
                                    sortbuf_count--;
176
20.5k
                                    continue;
177
20.5k
                                  }
178
35.1k
                              }
179
80.0k
                            j++;
180
80.0k
                          }
181
9.91M
                        if (s < s_end && sortbuf_count == 1)
182
3.05M
                          {
183
3.05M
                            ucs4_t combined =
184
3.05M
                              composer (sortbuf[0].code, uc);
185
3.05M
                            if (combined)
186
8.37k
                              {
187
8.37k
                                uc = combined;
188
8.37k
                                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.37k
                                sortbuf_count = 0;
193
8.37k
                              }
194
3.05M
                          }
195
9.91M
                      }
196
16.8M
                  }
197
198
26.8M
                for (size_t j = 0; j < sortbuf_count; j++)
199
9.99M
                  {
200
9.99M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
9.99M
                    if (length < allocated)
204
3.14M
                      {
205
3.14M
                        int ret =
206
3.14M
                          U_UCTOMB (result + length, muc, allocated - length);
207
3.14M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
3.14M
                        if (ret >= 0)
213
3.14M
                          {
214
3.14M
                            length += ret;
215
3.14M
                            goto done_appending;
216
3.14M
                          }
217
3.14M
                      }
218
6.85M
                    {
219
6.85M
                      size_t old_allocated = allocated;
220
6.85M
                      size_t new_allocated = 2 * old_allocated;
221
6.85M
                      if (new_allocated < 64)
222
6.85M
                        new_allocated = 64;
223
6.85M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
6.85M
                      {
226
6.85M
                        UNIT *larger_result;
227
6.85M
                        if (result == NULL)
228
6.85M
                          {
229
6.85M
                            larger_result =
230
6.85M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
6.85M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
6.85M
                          }
237
2.88k
                        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.88k
                        else
249
2.88k
                          {
250
2.88k
                            larger_result =
251
2.88k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
2.88k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
2.88k
                          }
258
6.85M
                        result = larger_result;
259
6.85M
                        allocated = new_allocated;
260
6.85M
                        {
261
6.85M
                          int ret =
262
6.85M
                            U_UCTOMB (result + length, muc, allocated - length);
263
6.85M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
6.85M
                          if (ret < 0)
269
0
                            abort ();
270
6.85M
                          length += ret;
271
6.85M
                          goto done_appending;
272
6.85M
                        }
273
6.85M
                      }
274
6.85M
                    }
275
9.99M
                   done_appending: ;
276
9.99M
                  }
277
278
                /* sortbuf is now empty.  */
279
16.8M
                sortbuf_count = 0;
280
16.8M
              }
281
282
16.9M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
6.91M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
10.0M
            if (sortbuf_count == sortbuf_allocated)
288
805
              {
289
805
                sortbuf_allocated = 2 * sortbuf_allocated;
290
805
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
805
                struct ucs4_with_ccc *new_sortbuf =
293
805
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
805
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
805
                memcpy (new_sortbuf, sortbuf,
300
805
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
805
                if (sortbuf != sortbuf_preallocated)
302
805
                  free (sortbuf);
303
805
                sortbuf = new_sortbuf;
304
805
              }
305
10.0M
            sortbuf[sortbuf_count].code = uc;
306
10.0M
            sortbuf[sortbuf_count].ccc = ccc;
307
10.0M
            sortbuf_count++;
308
309
10.0M
            i++;
310
10.0M
          }
311
312
16.9M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
6.91M
          break;
315
316
9.99M
        s += count;
317
9.99M
      }
318
6.91M
  }
319
320
6.91M
  if (length == 0)
321
60.8k
    {
322
60.8k
      if (result == NULL)
323
60.8k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
60.8k
          result = (UNIT *) malloc (1);
326
60.8k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
60.8k
        }
332
60.8k
    }
333
6.85M
  else if (result != resultbuf && length < allocated)
334
6.85M
    {
335
      /* Shrink the allocated memory if possible.  */
336
6.85M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
6.85M
      if (memory != NULL)
338
6.85M
        result = memory;
339
6.85M
    }
340
341
6.91M
  if (sortbuf_count > 0)
342
0
    abort ();
343
6.91M
  if (sortbuf != sortbuf_preallocated)
344
6.91M
    free (sortbuf);
345
346
6.91M
  *lengthp = length;
347
6.91M
  return result;
348
349
0
 fail:
350
0
  {
351
0
    int saved_errno = errno;
352
0
    if (sortbuf != sortbuf_preallocated)
353
0
      free (sortbuf);
354
0
    if (result != resultbuf)
355
0
      free (result);
356
0
    errno = saved_errno;
357
0
  }
358
  return NULL;
359
6.91M
}