Coverage Report

Created: 2026-10-16 07:06

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.2M
{
22
10.2M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
10.2M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
10.2M
  UNIT *result;
27
10.2M
  size_t allocated;
28
10.2M
  if (resultbuf == NULL)
29
10.2M
    {
30
10.2M
      result = NULL;
31
10.2M
      allocated = 0;
32
10.2M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
10.2M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
10.2M
  #define SORTBUF_PREALLOCATED 64
42
10.2M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
10.2M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
10.2M
    sortbuf_preallocated;
45
10.2M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
10.2M
  size_t sortbuf_count = 0;
47
48
10.2M
  {
49
10.2M
    const UNIT *s_end = s + n;
50
51
10.2M
    for (;;)
52
33.7M
      {
53
33.7M
        int count;
54
33.7M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
33.7M
        int decomposed_count;
56
57
33.7M
        if (s < s_end)
58
23.5M
          {
59
            /* Fetch the next character.  */
60
23.5M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
23.5M
            decomposed_count = 1;
62
63
            /* Decompose it, recursively.
64
               It would be possible to precompute the recursive decomposition
65
               and store it in a table.  But this would significantly increase
66
               the size of the decomposition tables, because for example for
67
               U+1FC1 the recursive canonical decomposition and the recursive
68
               compatibility decomposition are different.  */
69
56.5M
            for (int curr = 0; curr < decomposed_count; )
70
32.9M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
32.9M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
32.9M
                int curr_decomposed_count;
75
76
32.9M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
32.9M
                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.81M
                      {
88
2.81M
                        decomposed_count += shift;
89
2.81M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.84M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
26.2k
                          decomposed[j + shift] = decomposed[j];
93
2.81M
                      }
94
12.6M
                    for (; shift >= 0; shift--)
95
9.46M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.21M
                  }
97
29.7M
                else
98
29.7M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
29.7M
                    curr++;
101
29.7M
                  }
102
32.9M
              }
103
23.5M
          }
104
10.2M
        else
105
10.2M
          {
106
10.2M
            count = 0;
107
10.2M
            decomposed_count = 0;
108
10.2M
          }
109
110
33.7M
        int i = 0;
111
33.7M
        for (;;)
112
63.5M
          {
113
63.5M
            ucs4_t uc;
114
63.5M
            int ccc;
115
116
63.5M
            if (s < s_end)
117
53.3M
              {
118
                /* Fetch the next character from the decomposition.  */
119
53.3M
                if (i == decomposed_count)
120
23.5M
                  break;
121
29.7M
                uc = decomposed[i];
122
29.7M
                ccc = uc_combining_class (uc);
123
29.7M
              }
124
10.2M
            else
125
10.2M
              {
126
                /* End of string reached.  */
127
10.2M
                uc = 0;
128
10.2M
                ccc = 0;
129
10.2M
              }
130
131
40.0M
            if (ccc == 0)
132
36.8M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
36.8M
                if (sortbuf_count > 1)
136
1.68M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.68M
                                                           sortbuf + sortbuf_count);
138
139
36.8M
                if (composer != NULL)
140
36.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
36.8M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
26.6M
                      {
163
29.7M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.14M
                          {
165
3.14M
                            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.65M
                                  {
171
1.65M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.53M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
1.87M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.65M
                                    sortbuf_count--;
176
1.65M
                                    continue;
177
1.65M
                                  }
178
1.72M
                              }
179
1.48M
                            j++;
180
1.48M
                          }
181
26.6M
                        if (s < s_end && sortbuf_count == 1)
182
16.4M
                          {
183
16.4M
                            ucs4_t combined =
184
16.4M
                              composer (sortbuf[0].code, uc);
185
16.4M
                            if (combined)
186
16.4k
                              {
187
16.4k
                                uc = combined;
188
16.4k
                                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.4k
                                sortbuf_count = 0;
193
16.4k
                              }
194
16.4M
                          }
195
26.6M
                      }
196
36.8M
                  }
197
198
64.9M
                for (size_t j = 0; j < sortbuf_count; j++)
199
28.1M
                  {
200
28.1M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
28.1M
                    if (length < allocated)
204
17.9M
                      {
205
17.9M
                        int ret =
206
17.9M
                          U_UCTOMB (result + length, muc, allocated - length);
207
17.9M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
17.9M
                        if (ret >= 0)
213
17.9M
                          {
214
17.9M
                            length += ret;
215
17.9M
                            goto done_appending;
216
17.9M
                          }
217
17.9M
                      }
218
10.1M
                    {
219
10.1M
                      size_t old_allocated = allocated;
220
10.1M
                      size_t new_allocated = 2 * old_allocated;
221
10.1M
                      if (new_allocated < 64)
222
10.1M
                        new_allocated = 64;
223
10.1M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
10.1M
                      {
226
10.1M
                        UNIT *larger_result;
227
10.1M
                        if (result == NULL)
228
10.1M
                          {
229
10.1M
                            larger_result =
230
10.1M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
10.1M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
10.1M
                          }
237
14.9k
                        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
14.9k
                        else
249
14.9k
                          {
250
14.9k
                            larger_result =
251
14.9k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
14.9k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
14.9k
                          }
258
10.1M
                        result = larger_result;
259
10.1M
                        allocated = new_allocated;
260
10.1M
                        {
261
10.1M
                          int ret =
262
10.1M
                            U_UCTOMB (result + length, muc, allocated - length);
263
10.1M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
10.1M
                          if (ret < 0)
269
0
                            abort ();
270
10.1M
                          length += ret;
271
10.1M
                          goto done_appending;
272
10.1M
                        }
273
10.1M
                      }
274
10.1M
                    }
275
28.1M
                   done_appending: ;
276
28.1M
                  }
277
278
                /* sortbuf is now empty.  */
279
36.8M
                sortbuf_count = 0;
280
36.8M
              }
281
282
40.0M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
10.2M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
29.7M
            if (sortbuf_count == sortbuf_allocated)
288
1.98k
              {
289
1.98k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.98k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.98k
                struct ucs4_with_ccc *new_sortbuf =
293
1.98k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.98k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.98k
                memcpy (new_sortbuf, sortbuf,
300
1.98k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.98k
                if (sortbuf != sortbuf_preallocated)
302
1.98k
                  free (sortbuf);
303
1.98k
                sortbuf = new_sortbuf;
304
1.98k
              }
305
29.7M
            sortbuf[sortbuf_count].code = uc;
306
29.7M
            sortbuf[sortbuf_count].ccc = ccc;
307
29.7M
            sortbuf_count++;
308
309
29.7M
            i++;
310
29.7M
          }
311
312
33.7M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
10.2M
          break;
315
316
23.5M
        s += count;
317
23.5M
      }
318
10.2M
  }
319
320
10.2M
  if (length == 0)
321
95.8k
    {
322
95.8k
      if (result == NULL)
323
95.8k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
95.8k
          result = (UNIT *) malloc (1);
326
95.8k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
95.8k
        }
332
95.8k
    }
333
10.1M
  else if (result != resultbuf && length < allocated)
334
10.1M
    {
335
      /* Shrink the allocated memory if possible.  */
336
10.1M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
10.1M
      if (memory != NULL)
338
10.1M
        result = memory;
339
10.1M
    }
340
341
10.2M
  if (sortbuf_count > 0)
342
0
    abort ();
343
10.2M
  if (sortbuf != sortbuf_preallocated)
344
10.2M
    free (sortbuf);
345
346
10.2M
  *lengthp = length;
347
10.2M
  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.2M
}
u8_normalize
Line
Count
Source
21
3.34M
{
22
3.34M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
3.34M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
3.34M
  UNIT *result;
27
3.34M
  size_t allocated;
28
3.34M
  if (resultbuf == NULL)
29
3.34M
    {
30
3.34M
      result = NULL;
31
3.34M
      allocated = 0;
32
3.34M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
3.34M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
3.34M
  #define SORTBUF_PREALLOCATED 64
42
3.34M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
3.34M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
3.34M
    sortbuf_preallocated;
45
3.34M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
3.34M
  size_t sortbuf_count = 0;
47
48
3.34M
  {
49
3.34M
    const UNIT *s_end = s + n;
50
51
3.34M
    for (;;)
52
16.8M
      {
53
16.8M
        int count;
54
16.8M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
16.8M
        int decomposed_count;
56
57
16.8M
        if (s < s_end)
58
13.5M
          {
59
            /* Fetch the next character.  */
60
13.5M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
13.5M
            decomposed_count = 1;
62
63
            /* Decompose it, recursively.
64
               It would be possible to precompute the recursive decomposition
65
               and store it in a table.  But this would significantly increase
66
               the size of the decomposition tables, because for example for
67
               U+1FC1 the recursive canonical decomposition and the recursive
68
               compatibility decomposition are different.  */
69
36.5M
            for (int curr = 0; curr < decomposed_count; )
70
22.9M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
22.9M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
22.9M
                int curr_decomposed_count;
75
76
22.9M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
22.9M
                if (curr_decomposed_count >= 0)
78
3.18M
                  {
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.18M
                    int shift = curr_decomposed_count - 1;
83
84
3.18M
                    if (shift < 0)
85
0
                      abort ();
86
3.18M
                    if (shift > 0)
87
2.78M
                      {
88
2.78M
                        decomposed_count += shift;
89
2.78M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.79M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
16.2k
                          decomposed[j + shift] = decomposed[j];
93
2.78M
                      }
94
12.5M
                    for (; shift >= 0; shift--)
95
9.40M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.18M
                  }
97
19.7M
                else
98
19.7M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
19.7M
                    curr++;
101
19.7M
                  }
102
22.9M
              }
103
13.5M
          }
104
3.34M
        else
105
3.34M
          {
106
3.34M
            count = 0;
107
3.34M
            decomposed_count = 0;
108
3.34M
          }
109
110
16.8M
        int i = 0;
111
16.8M
        for (;;)
112
36.6M
          {
113
36.6M
            ucs4_t uc;
114
36.6M
            int ccc;
115
116
36.6M
            if (s < s_end)
117
33.3M
              {
118
                /* Fetch the next character from the decomposition.  */
119
33.3M
                if (i == decomposed_count)
120
13.5M
                  break;
121
19.7M
                uc = decomposed[i];
122
19.7M
                ccc = uc_combining_class (uc);
123
19.7M
              }
124
3.34M
            else
125
3.34M
              {
126
                /* End of string reached.  */
127
3.34M
                uc = 0;
128
3.34M
                ccc = 0;
129
3.34M
              }
130
131
23.1M
            if (ccc == 0)
132
20.0M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
20.0M
                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.0M
                if (composer != NULL)
140
20.0M
                  {
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.0M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
16.7M
                      {
163
19.7M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.04M
                          {
165
3.04M
                            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.63M
                                  {
171
1.63M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.49M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
1.86M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.63M
                                    sortbuf_count--;
176
1.63M
                                    continue;
177
1.63M
                                  }
178
1.68M
                              }
179
1.40M
                            j++;
180
1.40M
                          }
181
16.7M
                        if (s < s_end && sortbuf_count == 1)
182
13.3M
                          {
183
13.3M
                            ucs4_t combined =
184
13.3M
                              composer (sortbuf[0].code, uc);
185
13.3M
                            if (combined)
186
7.43k
                              {
187
7.43k
                                uc = combined;
188
7.43k
                                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.43k
                                sortbuf_count = 0;
193
7.43k
                              }
194
13.3M
                          }
195
16.7M
                      }
196
20.0M
                  }
197
198
38.1M
                for (size_t j = 0; j < sortbuf_count; j++)
199
18.1M
                  {
200
18.1M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
18.1M
                    if (length < allocated)
204
14.7M
                      {
205
14.7M
                        int ret =
206
14.7M
                          U_UCTOMB (result + length, muc, allocated - length);
207
14.7M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
14.7M
                        if (ret >= 0)
213
14.7M
                          {
214
14.7M
                            length += ret;
215
14.7M
                            goto done_appending;
216
14.7M
                          }
217
14.7M
                      }
218
3.35M
                    {
219
3.35M
                      size_t old_allocated = allocated;
220
3.35M
                      size_t new_allocated = 2 * old_allocated;
221
3.35M
                      if (new_allocated < 64)
222
3.34M
                        new_allocated = 64;
223
3.35M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
3.35M
                      {
226
3.35M
                        UNIT *larger_result;
227
3.35M
                        if (result == NULL)
228
3.34M
                          {
229
3.34M
                            larger_result =
230
3.34M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
3.34M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
3.34M
                          }
237
12.3k
                        else if (result == resultbuf)
238
0
                          {
239
0
                            larger_result =
240
0
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
241
0
                            if (larger_result == NULL)
242
0
                              {
243
0
                                errno = ENOMEM;
244
0
                                goto fail;
245
0
                              }
246
0
                            U_CPY (larger_result, resultbuf, length);
247
0
                          }
248
12.3k
                        else
249
12.3k
                          {
250
12.3k
                            larger_result =
251
12.3k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
12.3k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
12.3k
                          }
258
3.35M
                        result = larger_result;
259
3.35M
                        allocated = new_allocated;
260
3.35M
                        {
261
3.35M
                          int ret =
262
3.35M
                            U_UCTOMB (result + length, muc, allocated - length);
263
3.35M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
3.35M
                          if (ret < 0)
269
0
                            abort ();
270
3.35M
                          length += ret;
271
3.35M
                          goto done_appending;
272
3.35M
                        }
273
3.35M
                      }
274
3.35M
                    }
275
18.1M
                   done_appending: ;
276
18.1M
                  }
277
278
                /* sortbuf is now empty.  */
279
20.0M
                sortbuf_count = 0;
280
20.0M
              }
281
282
23.1M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
3.34M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
19.7M
            if (sortbuf_count == sortbuf_allocated)
288
1.16k
              {
289
1.16k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.16k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.16k
                struct ucs4_with_ccc *new_sortbuf =
293
1.16k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.16k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.16k
                memcpy (new_sortbuf, sortbuf,
300
1.16k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.16k
                if (sortbuf != sortbuf_preallocated)
302
1.16k
                  free (sortbuf);
303
1.16k
                sortbuf = new_sortbuf;
304
1.16k
              }
305
19.7M
            sortbuf[sortbuf_count].code = uc;
306
19.7M
            sortbuf[sortbuf_count].ccc = ccc;
307
19.7M
            sortbuf_count++;
308
309
19.7M
            i++;
310
19.7M
          }
311
312
16.8M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
3.34M
          break;
315
316
13.5M
        s += count;
317
13.5M
      }
318
3.34M
  }
319
320
3.34M
  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.34M
  else if (result != resultbuf && length < allocated)
334
3.34M
    {
335
      /* Shrink the allocated memory if possible.  */
336
3.34M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
3.34M
      if (memory != NULL)
338
3.34M
        result = memory;
339
3.34M
    }
340
341
3.34M
  if (sortbuf_count > 0)
342
0
    abort ();
343
3.34M
  if (sortbuf != sortbuf_preallocated)
344
3.34M
    free (sortbuf);
345
346
3.34M
  *lengthp = length;
347
3.34M
  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.34M
}
u32_normalize
Line
Count
Source
21
6.88M
{
22
6.88M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
6.88M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
6.88M
  UNIT *result;
27
6.88M
  size_t allocated;
28
6.88M
  if (resultbuf == NULL)
29
6.88M
    {
30
6.88M
      result = NULL;
31
6.88M
      allocated = 0;
32
6.88M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
6.88M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
6.88M
  #define SORTBUF_PREALLOCATED 64
42
6.88M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
6.88M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
6.88M
    sortbuf_preallocated;
45
6.88M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
6.88M
  size_t sortbuf_count = 0;
47
48
6.88M
  {
49
6.88M
    const UNIT *s_end = s + n;
50
51
6.88M
    for (;;)
52
16.8M
      {
53
16.8M
        int count;
54
16.8M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
16.8M
        int decomposed_count;
56
57
16.8M
        if (s < s_end)
58
9.97M
          {
59
            /* Fetch the next character.  */
60
9.97M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
9.97M
            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
32.0k
                  {
79
                    /* Move curr_decomposed[0..curr_decomposed_count-1] over
80
                       decomposed[curr], making room.  It's not worth using
81
                       memcpy() here, since the counts are so small.  */
82
32.0k
                    int shift = curr_decomposed_count - 1;
83
84
32.0k
                    if (shift < 0)
85
0
                      abort ();
86
32.0k
                    if (shift > 0)
87
31.8k
                      {
88
31.8k
                        decomposed_count += shift;
89
31.8k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
41.7k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
9.90k
                          decomposed[j + shift] = decomposed[j];
93
31.8k
                      }
94
95.9k
                    for (; shift >= 0; shift--)
95
63.9k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
32.0k
                  }
97
10.0M
                else
98
10.0M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
10.0M
                    curr++;
101
10.0M
                  }
102
10.0M
              }
103
9.97M
          }
104
6.88M
        else
105
6.88M
          {
106
6.88M
            count = 0;
107
6.88M
            decomposed_count = 0;
108
6.88M
          }
109
110
16.8M
        int i = 0;
111
16.8M
        for (;;)
112
26.8M
          {
113
26.8M
            ucs4_t uc;
114
26.8M
            int ccc;
115
116
26.8M
            if (s < s_end)
117
19.9M
              {
118
                /* Fetch the next character from the decomposition.  */
119
19.9M
                if (i == decomposed_count)
120
9.97M
                  break;
121
10.0M
                uc = decomposed[i];
122
10.0M
                ccc = uc_combining_class (uc);
123
10.0M
              }
124
6.88M
            else
125
6.88M
              {
126
                /* End of string reached.  */
127
6.88M
                uc = 0;
128
6.88M
                ccc = 0;
129
6.88M
              }
130
131
16.8M
            if (ccc == 0)
132
16.7M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
16.7M
                if (sortbuf_count > 1)
136
24.7k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
24.7k
                                                           sortbuf + sortbuf_count);
138
139
16.7M
                if (composer != NULL)
140
16.7M
                  {
141
                    /* Attempt to combine decomposed characters, as specified
142
                       in the Unicode Standard Annex #15 "Unicode Normalization
143
                       Forms".  We need to check
144
                         1. whether the first accumulated character is a
145
                            "starter" (i.e. has ccc = 0).  This is usually the
146
                            case.  But when the string starts with a
147
                            non-starter, the sortbuf also starts with a
148
                            non-starter.  Btw, this check could also be
149
                            omitted, because the composition table has only
150
                            entries (code1, code2) for which code1 is a
151
                            starter; if the first accumulated character is not
152
                            a starter, no lookup will succeed.
153
                         2. If the sortbuf has more than one character, check
154
                            for each of these characters that are not "blocked"
155
                            from the starter (i.e. have a ccc that is higher
156
                            than the ccc of the previous character) whether it
157
                            can be combined with the first character.
158
                         3. If only one character is left in sortbuf, check
159
                            whether it can be combined with the next character
160
                            (also a starter).  */
161
16.7M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
9.90M
                      {
163
10.0M
                        for (size_t j = 1; j < sortbuf_count; )
164
99.8k
                          {
165
99.8k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
35.8k
                              {
167
35.8k
                                ucs4_t combined =
168
35.8k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
35.8k
                                if (combined)
170
21.1k
                                  {
171
21.1k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
35.5k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
14.4k
                                      sortbuf[k - 1] = sortbuf[k];
175
21.1k
                                    sortbuf_count--;
176
21.1k
                                    continue;
177
21.1k
                                  }
178
35.8k
                              }
179
78.7k
                            j++;
180
78.7k
                          }
181
9.90M
                        if (s < s_end && sortbuf_count == 1)
182
3.10M
                          {
183
3.10M
                            ucs4_t combined =
184
3.10M
                              composer (sortbuf[0].code, uc);
185
3.10M
                            if (combined)
186
8.99k
                              {
187
8.99k
                                uc = combined;
188
8.99k
                                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.99k
                                sortbuf_count = 0;
193
8.99k
                              }
194
3.10M
                          }
195
9.90M
                      }
196
16.7M
                  }
197
198
26.7M
                for (size_t j = 0; j < sortbuf_count; j++)
199
9.97M
                  {
200
9.97M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
9.97M
                    if (length < allocated)
204
3.18M
                      {
205
3.18M
                        int ret =
206
3.18M
                          U_UCTOMB (result + length, muc, allocated - length);
207
3.18M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
3.18M
                        if (ret >= 0)
213
3.18M
                          {
214
3.18M
                            length += ret;
215
3.18M
                            goto done_appending;
216
3.18M
                          }
217
3.18M
                      }
218
6.79M
                    {
219
6.79M
                      size_t old_allocated = allocated;
220
6.79M
                      size_t new_allocated = 2 * old_allocated;
221
6.79M
                      if (new_allocated < 64)
222
6.79M
                        new_allocated = 64;
223
6.79M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
6.79M
                      {
226
6.79M
                        UNIT *larger_result;
227
6.79M
                        if (result == NULL)
228
6.79M
                          {
229
6.79M
                            larger_result =
230
6.79M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
6.79M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
6.79M
                          }
237
2.65k
                        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.65k
                        else
249
2.65k
                          {
250
2.65k
                            larger_result =
251
2.65k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
2.65k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
2.65k
                          }
258
6.79M
                        result = larger_result;
259
6.79M
                        allocated = new_allocated;
260
6.79M
                        {
261
6.79M
                          int ret =
262
6.79M
                            U_UCTOMB (result + length, muc, allocated - length);
263
6.79M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
6.79M
                          if (ret < 0)
269
0
                            abort ();
270
6.79M
                          length += ret;
271
6.79M
                          goto done_appending;
272
6.79M
                        }
273
6.79M
                      }
274
6.79M
                    }
275
9.97M
                   done_appending: ;
276
9.97M
                  }
277
278
                /* sortbuf is now empty.  */
279
16.7M
                sortbuf_count = 0;
280
16.7M
              }
281
282
16.8M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
6.88M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
10.0M
            if (sortbuf_count == sortbuf_allocated)
288
817
              {
289
817
                sortbuf_allocated = 2 * sortbuf_allocated;
290
817
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
817
                struct ucs4_with_ccc *new_sortbuf =
293
817
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
817
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
817
                memcpy (new_sortbuf, sortbuf,
300
817
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
817
                if (sortbuf != sortbuf_preallocated)
302
817
                  free (sortbuf);
303
817
                sortbuf = new_sortbuf;
304
817
              }
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.8M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
6.88M
          break;
315
316
9.97M
        s += count;
317
9.97M
      }
318
6.88M
  }
319
320
6.88M
  if (length == 0)
321
95.8k
    {
322
95.8k
      if (result == NULL)
323
95.8k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
95.8k
          result = (UNIT *) malloc (1);
326
95.8k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
95.8k
        }
332
95.8k
    }
333
6.79M
  else if (result != resultbuf && length < allocated)
334
6.79M
    {
335
      /* Shrink the allocated memory if possible.  */
336
6.79M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
6.79M
      if (memory != NULL)
338
6.79M
        result = memory;
339
6.79M
    }
340
341
6.88M
  if (sortbuf_count > 0)
342
0
    abort ();
343
6.88M
  if (sortbuf != sortbuf_preallocated)
344
6.88M
    free (sortbuf);
345
346
6.88M
  *lengthp = length;
347
6.88M
  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.88M
}