Coverage Report

Created: 2026-09-01 06:47

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.5M
{
22
10.5M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
10.5M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
10.5M
  UNIT *result;
27
10.5M
  size_t allocated;
28
10.5M
  if (resultbuf == NULL)
29
10.5M
    {
30
10.5M
      result = NULL;
31
10.5M
      allocated = 0;
32
10.5M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
10.5M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
10.5M
  #define SORTBUF_PREALLOCATED 64
42
10.5M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
10.5M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
10.5M
    sortbuf_preallocated;
45
10.5M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
10.5M
  size_t sortbuf_count = 0;
47
48
10.5M
  {
49
10.5M
    const UNIT *s_end = s + n;
50
51
10.5M
    for (;;)
52
35.2M
      {
53
35.2M
        int count;
54
35.2M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
35.2M
        int decomposed_count;
56
57
35.2M
        if (s < s_end)
58
24.7M
          {
59
            /* Fetch the next character.  */
60
24.7M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
24.7M
            decomposed_count = 1;
62
63
            /* Decompose it, recursively.
64
               It would be possible to precompute the recursive decomposition
65
               and store it in a table.  But this would significantly increase
66
               the size of the decomposition tables, because for example for
67
               U+1FC1 the recursive canonical decomposition and the recursive
68
               compatibility decomposition are different.  */
69
59.1M
            for (int curr = 0; curr < decomposed_count; )
70
34.3M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
34.3M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
34.3M
                int curr_decomposed_count;
75
76
34.3M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
34.3M
                if (curr_decomposed_count >= 0)
78
3.26M
                  {
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.26M
                    int shift = curr_decomposed_count - 1;
83
84
3.26M
                    if (shift < 0)
85
0
                      abort ();
86
3.26M
                    if (shift > 0)
87
2.87M
                      {
88
2.87M
                        decomposed_count += shift;
89
2.87M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.90M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
29.6k
                          decomposed[j + shift] = decomposed[j];
93
2.87M
                      }
94
12.8M
                    for (; shift >= 0; shift--)
95
9.62M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.26M
                  }
97
31.1M
                else
98
31.1M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
31.1M
                    curr++;
101
31.1M
                  }
102
34.3M
              }
103
24.7M
          }
104
10.5M
        else
105
10.5M
          {
106
10.5M
            count = 0;
107
10.5M
            decomposed_count = 0;
108
10.5M
          }
109
110
35.2M
        int i = 0;
111
35.2M
        for (;;)
112
66.4M
          {
113
66.4M
            ucs4_t uc;
114
66.4M
            int ccc;
115
116
66.4M
            if (s < s_end)
117
55.9M
              {
118
                /* Fetch the next character from the decomposition.  */
119
55.9M
                if (i == decomposed_count)
120
24.7M
                  break;
121
31.1M
                uc = decomposed[i];
122
31.1M
                ccc = uc_combining_class (uc);
123
31.1M
              }
124
10.5M
            else
125
10.5M
              {
126
                /* End of string reached.  */
127
10.5M
                uc = 0;
128
10.5M
                ccc = 0;
129
10.5M
              }
130
131
41.6M
            if (ccc == 0)
132
38.2M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
38.2M
                if (sortbuf_count > 1)
136
1.68M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.68M
                                                           sortbuf + sortbuf_count);
138
139
38.2M
                if (composer != NULL)
140
38.2M
                  {
141
                    /* Attempt to combine decomposed characters, as specified
142
                       in the Unicode Standard Annex #15 "Unicode Normalization
143
                       Forms".  We need to check
144
                         1. whether the first accumulated character is a
145
                            "starter" (i.e. has ccc = 0).  This is usually the
146
                            case.  But when the string starts with a
147
                            non-starter, the sortbuf also starts with a
148
                            non-starter.  Btw, this check could also be
149
                            omitted, because the composition table has only
150
                            entries (code1, code2) for which code1 is a
151
                            starter; if the first accumulated character is not
152
                            a starter, no lookup will succeed.
153
                         2. If the sortbuf has more than one character, check
154
                            for each of these characters that are not "blocked"
155
                            from the starter (i.e. have a ccc that is higher
156
                            than the ccc of the previous character) whether it
157
                            can be combined with the first character.
158
                         3. If only one character is left in sortbuf, check
159
                            whether it can be combined with the next character
160
                            (also a starter).  */
161
38.2M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
27.7M
                      {
163
31.1M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.32M
                          {
165
3.32M
                            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.64M
                                  {
171
1.64M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.73M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.09M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.64M
                                    sortbuf_count--;
176
1.64M
                                    continue;
177
1.64M
                                  }
178
1.72M
                              }
179
1.67M
                            j++;
180
1.67M
                          }
181
27.7M
                        if (s < s_end && sortbuf_count == 1)
182
17.3M
                          {
183
17.3M
                            ucs4_t combined =
184
17.3M
                              composer (sortbuf[0].code, uc);
185
17.3M
                            if (combined)
186
19.0k
                              {
187
19.0k
                                uc = combined;
188
19.0k
                                ccc = 0;
189
                                /* uc could be further combined with subsequent
190
                                   characters.  So don't put it into sortbuf[0] in
191
                                   this round, only in the next round.  */
192
19.0k
                                sortbuf_count = 0;
193
19.0k
                              }
194
17.3M
                          }
195
27.7M
                      }
196
38.2M
                  }
197
198
67.7M
                for (size_t j = 0; j < sortbuf_count; j++)
199
29.4M
                  {
200
29.4M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
29.4M
                    if (length < allocated)
204
19.0M
                      {
205
19.0M
                        int ret =
206
19.0M
                          U_UCTOMB (result + length, muc, allocated - length);
207
19.0M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
19.0M
                        if (ret >= 0)
213
19.0M
                          {
214
19.0M
                            length += ret;
215
19.0M
                            goto done_appending;
216
19.0M
                          }
217
19.0M
                      }
218
10.4M
                    {
219
10.4M
                      size_t old_allocated = allocated;
220
10.4M
                      size_t new_allocated = 2 * old_allocated;
221
10.4M
                      if (new_allocated < 64)
222
10.4M
                        new_allocated = 64;
223
10.4M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
10.4M
                      {
226
10.4M
                        UNIT *larger_result;
227
10.4M
                        if (result == NULL)
228
10.4M
                          {
229
10.4M
                            larger_result =
230
10.4M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
10.4M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
10.4M
                          }
237
28.8k
                        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
28.8k
                        else
249
28.8k
                          {
250
28.8k
                            larger_result =
251
28.8k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
28.8k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
28.8k
                          }
258
10.4M
                        result = larger_result;
259
10.4M
                        allocated = new_allocated;
260
10.4M
                        {
261
10.4M
                          int ret =
262
10.4M
                            U_UCTOMB (result + length, muc, allocated - length);
263
10.4M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
10.4M
                          if (ret < 0)
269
0
                            abort ();
270
10.4M
                          length += ret;
271
10.4M
                          goto done_appending;
272
10.4M
                        }
273
10.4M
                      }
274
10.4M
                    }
275
29.4M
                   done_appending: ;
276
29.4M
                  }
277
278
                /* sortbuf is now empty.  */
279
38.2M
                sortbuf_count = 0;
280
38.2M
              }
281
282
41.6M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
10.5M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
31.1M
            if (sortbuf_count == sortbuf_allocated)
288
2.12k
              {
289
2.12k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
2.12k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
2.12k
                struct ucs4_with_ccc *new_sortbuf =
293
2.12k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
2.12k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
2.12k
                memcpy (new_sortbuf, sortbuf,
300
2.12k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
2.12k
                if (sortbuf != sortbuf_preallocated)
302
2.12k
                  free (sortbuf);
303
2.12k
                sortbuf = new_sortbuf;
304
2.12k
              }
305
31.1M
            sortbuf[sortbuf_count].code = uc;
306
31.1M
            sortbuf[sortbuf_count].ccc = ccc;
307
31.1M
            sortbuf_count++;
308
309
31.1M
            i++;
310
31.1M
          }
311
312
35.2M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
10.5M
          break;
315
316
24.7M
        s += count;
317
24.7M
      }
318
10.5M
  }
319
320
10.5M
  if (length == 0)
321
74.4k
    {
322
74.4k
      if (result == NULL)
323
74.4k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
74.4k
          result = (UNIT *) malloc (1);
326
74.4k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
74.4k
        }
332
74.4k
    }
333
10.4M
  else if (result != resultbuf && length < allocated)
334
10.4M
    {
335
      /* Shrink the allocated memory if possible.  */
336
10.4M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
10.4M
      if (memory != NULL)
338
10.4M
        result = memory;
339
10.4M
    }
340
341
10.5M
  if (sortbuf_count > 0)
342
0
    abort ();
343
10.5M
  if (sortbuf != sortbuf_preallocated)
344
10.5M
    free (sortbuf);
345
346
10.5M
  *lengthp = length;
347
10.5M
  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.5M
}
u8_normalize
Line
Count
Source
21
3.45M
{
22
3.45M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
3.45M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
3.45M
  UNIT *result;
27
3.45M
  size_t allocated;
28
3.45M
  if (resultbuf == NULL)
29
3.45M
    {
30
3.45M
      result = NULL;
31
3.45M
      allocated = 0;
32
3.45M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
3.45M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
3.45M
  #define SORTBUF_PREALLOCATED 64
42
3.45M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
3.45M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
3.45M
    sortbuf_preallocated;
45
3.45M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
3.45M
  size_t sortbuf_count = 0;
47
48
3.45M
  {
49
3.45M
    const UNIT *s_end = s + n;
50
51
3.45M
    for (;;)
52
17.9M
      {
53
17.9M
        int count;
54
17.9M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
17.9M
        int decomposed_count;
56
57
17.9M
        if (s < s_end)
58
14.4M
          {
59
            /* Fetch the next character.  */
60
14.4M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
14.4M
            decomposed_count = 1;
62
63
            /* Decompose it, recursively.
64
               It would be possible to precompute the recursive decomposition
65
               and store it in a table.  But this would significantly increase
66
               the size of the decomposition tables, because for example for
67
               U+1FC1 the recursive canonical decomposition and the recursive
68
               compatibility decomposition are different.  */
69
38.4M
            for (int curr = 0; curr < decomposed_count; )
70
24.0M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
24.0M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
24.0M
                int curr_decomposed_count;
75
76
24.0M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
24.0M
                if (curr_decomposed_count >= 0)
78
3.22M
                  {
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.22M
                    int shift = curr_decomposed_count - 1;
83
84
3.22M
                    if (shift < 0)
85
0
                      abort ();
86
3.22M
                    if (shift > 0)
87
2.83M
                      {
88
2.83M
                        decomposed_count += shift;
89
2.83M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.85M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
18.8k
                          decomposed[j + shift] = decomposed[j];
93
2.83M
                      }
94
12.7M
                    for (; shift >= 0; shift--)
95
9.55M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.22M
                  }
97
20.7M
                else
98
20.7M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
20.7M
                    curr++;
101
20.7M
                  }
102
24.0M
              }
103
14.4M
          }
104
3.45M
        else
105
3.45M
          {
106
3.45M
            count = 0;
107
3.45M
            decomposed_count = 0;
108
3.45M
          }
109
110
17.9M
        int i = 0;
111
17.9M
        for (;;)
112
38.7M
          {
113
38.7M
            ucs4_t uc;
114
38.7M
            int ccc;
115
116
38.7M
            if (s < s_end)
117
35.2M
              {
118
                /* Fetch the next character from the decomposition.  */
119
35.2M
                if (i == decomposed_count)
120
14.4M
                  break;
121
20.7M
                uc = decomposed[i];
122
20.7M
                ccc = uc_combining_class (uc);
123
20.7M
              }
124
3.45M
            else
125
3.45M
              {
126
                /* End of string reached.  */
127
3.45M
                uc = 0;
128
3.45M
                ccc = 0;
129
3.45M
              }
130
131
24.2M
            if (ccc == 0)
132
21.0M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
21.0M
                if (sortbuf_count > 1)
136
1.65M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.65M
                                                           sortbuf + sortbuf_count);
138
139
21.0M
                if (composer != NULL)
140
21.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
21.0M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
17.5M
                      {
163
20.7M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.17M
                          {
165
3.17M
                            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.62M
                                  {
171
1.62M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.69M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.06M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.62M
                                    sortbuf_count--;
176
1.62M
                                    continue;
177
1.62M
                                  }
178
1.68M
                              }
179
1.54M
                            j++;
180
1.54M
                          }
181
17.5M
                        if (s < s_end && sortbuf_count == 1)
182
14.0M
                          {
183
14.0M
                            ucs4_t combined =
184
14.0M
                              composer (sortbuf[0].code, uc);
185
14.0M
                            if (combined)
186
9.33k
                              {
187
9.33k
                                uc = combined;
188
9.33k
                                ccc = 0;
189
                                /* uc could be further combined with subsequent
190
                                   characters.  So don't put it into sortbuf[0] in
191
                                   this round, only in the next round.  */
192
9.33k
                                sortbuf_count = 0;
193
9.33k
                              }
194
14.0M
                          }
195
17.5M
                      }
196
21.0M
                  }
197
198
40.2M
                for (size_t j = 0; j < sortbuf_count; j++)
199
19.1M
                  {
200
19.1M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
19.1M
                    if (length < allocated)
204
15.6M
                      {
205
15.6M
                        int ret =
206
15.6M
                          U_UCTOMB (result + length, muc, allocated - length);
207
15.6M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
15.6M
                        if (ret >= 0)
213
15.6M
                          {
214
15.6M
                            length += ret;
215
15.6M
                            goto done_appending;
216
15.6M
                          }
217
15.6M
                      }
218
3.47M
                    {
219
3.47M
                      size_t old_allocated = allocated;
220
3.47M
                      size_t new_allocated = 2 * old_allocated;
221
3.47M
                      if (new_allocated < 64)
222
3.45M
                        new_allocated = 64;
223
3.47M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
3.47M
                      {
226
3.47M
                        UNIT *larger_result;
227
3.47M
                        if (result == NULL)
228
3.45M
                          {
229
3.45M
                            larger_result =
230
3.45M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
3.45M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
3.45M
                          }
237
25.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
25.3k
                        else
249
25.3k
                          {
250
25.3k
                            larger_result =
251
25.3k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
25.3k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
25.3k
                          }
258
3.47M
                        result = larger_result;
259
3.47M
                        allocated = new_allocated;
260
3.47M
                        {
261
3.47M
                          int ret =
262
3.47M
                            U_UCTOMB (result + length, muc, allocated - length);
263
3.47M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
3.47M
                          if (ret < 0)
269
0
                            abort ();
270
3.47M
                          length += ret;
271
3.47M
                          goto done_appending;
272
3.47M
                        }
273
3.47M
                      }
274
3.47M
                    }
275
19.1M
                   done_appending: ;
276
19.1M
                  }
277
278
                /* sortbuf is now empty.  */
279
21.0M
                sortbuf_count = 0;
280
21.0M
              }
281
282
24.2M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
3.45M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
20.7M
            if (sortbuf_count == sortbuf_allocated)
288
1.20k
              {
289
1.20k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.20k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.20k
                struct ucs4_with_ccc *new_sortbuf =
293
1.20k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.20k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.20k
                memcpy (new_sortbuf, sortbuf,
300
1.20k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.20k
                if (sortbuf != sortbuf_preallocated)
302
1.20k
                  free (sortbuf);
303
1.20k
                sortbuf = new_sortbuf;
304
1.20k
              }
305
20.7M
            sortbuf[sortbuf_count].code = uc;
306
20.7M
            sortbuf[sortbuf_count].ccc = ccc;
307
20.7M
            sortbuf_count++;
308
309
20.7M
            i++;
310
20.7M
          }
311
312
17.9M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
3.45M
          break;
315
316
14.4M
        s += count;
317
14.4M
      }
318
3.45M
  }
319
320
3.45M
  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.45M
  else if (result != resultbuf && length < allocated)
334
3.45M
    {
335
      /* Shrink the allocated memory if possible.  */
336
3.45M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
3.45M
      if (memory != NULL)
338
3.45M
        result = memory;
339
3.45M
    }
340
341
3.45M
  if (sortbuf_count > 0)
342
0
    abort ();
343
3.45M
  if (sortbuf != sortbuf_preallocated)
344
3.45M
    free (sortbuf);
345
346
3.45M
  *lengthp = length;
347
3.45M
  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.45M
}
u32_normalize
Line
Count
Source
21
7.04M
{
22
7.04M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
7.04M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
7.04M
  UNIT *result;
27
7.04M
  size_t allocated;
28
7.04M
  if (resultbuf == NULL)
29
7.04M
    {
30
7.04M
      result = NULL;
31
7.04M
      allocated = 0;
32
7.04M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
7.04M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
7.04M
  #define SORTBUF_PREALLOCATED 64
42
7.04M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
7.04M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
7.04M
    sortbuf_preallocated;
45
7.04M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
7.04M
  size_t sortbuf_count = 0;
47
48
7.04M
  {
49
7.04M
    const UNIT *s_end = s + n;
50
51
7.04M
    for (;;)
52
17.3M
      {
53
17.3M
        int count;
54
17.3M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
17.3M
        int decomposed_count;
56
57
17.3M
        if (s < s_end)
58
10.3M
          {
59
            /* Fetch the next character.  */
60
10.3M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
10.3M
            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.6M
            for (int curr = 0; curr < decomposed_count; )
70
10.3M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
10.3M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
10.3M
                int curr_decomposed_count;
75
76
10.3M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
10.3M
                if (curr_decomposed_count >= 0)
78
36.7k
                  {
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
36.7k
                    int shift = curr_decomposed_count - 1;
83
84
36.7k
                    if (shift < 0)
85
0
                      abort ();
86
36.7k
                    if (shift > 0)
87
36.4k
                      {
88
36.4k
                        decomposed_count += shift;
89
36.4k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
47.2k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
10.8k
                          decomposed[j + shift] = decomposed[j];
93
36.4k
                      }
94
109k
                    for (; shift >= 0; shift--)
95
73.1k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
36.7k
                  }
97
10.3M
                else
98
10.3M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
10.3M
                    curr++;
101
10.3M
                  }
102
10.3M
              }
103
10.3M
          }
104
7.04M
        else
105
7.04M
          {
106
7.04M
            count = 0;
107
7.04M
            decomposed_count = 0;
108
7.04M
          }
109
110
17.3M
        int i = 0;
111
17.3M
        for (;;)
112
27.7M
          {
113
27.7M
            ucs4_t uc;
114
27.7M
            int ccc;
115
116
27.7M
            if (s < s_end)
117
20.6M
              {
118
                /* Fetch the next character from the decomposition.  */
119
20.6M
                if (i == decomposed_count)
120
10.3M
                  break;
121
10.3M
                uc = decomposed[i];
122
10.3M
                ccc = uc_combining_class (uc);
123
10.3M
              }
124
7.04M
            else
125
7.04M
              {
126
                /* End of string reached.  */
127
7.04M
                uc = 0;
128
7.04M
                ccc = 0;
129
7.04M
              }
130
131
17.3M
            if (ccc == 0)
132
17.2M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
17.2M
                if (sortbuf_count > 1)
136
27.9k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
27.9k
                                                           sortbuf + sortbuf_count);
138
139
17.2M
                if (composer != NULL)
140
17.2M
                  {
141
                    /* Attempt to combine decomposed characters, as specified
142
                       in the Unicode Standard Annex #15 "Unicode Normalization
143
                       Forms".  We need to check
144
                         1. whether the first accumulated character is a
145
                            "starter" (i.e. has ccc = 0).  This is usually the
146
                            case.  But when the string starts with a
147
                            non-starter, the sortbuf also starts with a
148
                            non-starter.  Btw, this check could also be
149
                            omitted, because the composition table has only
150
                            entries (code1, code2) for which code1 is a
151
                            starter; if the first accumulated character is not
152
                            a starter, no lookup will succeed.
153
                         2. If the sortbuf has more than one character, check
154
                            for each of these characters that are not "blocked"
155
                            from the starter (i.e. have a ccc that is higher
156
                            than the ccc of the previous character) whether it
157
                            can be combined with the first character.
158
                         3. If only one character is left in sortbuf, check
159
                            whether it can be combined with the next character
160
                            (also a starter).  */
161
17.2M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
10.1M
                      {
163
10.3M
                        for (size_t j = 1; j < sortbuf_count; )
164
149k
                          {
165
149k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
41.3k
                              {
167
41.3k
                                ucs4_t combined =
168
41.3k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
41.3k
                                if (combined)
170
23.6k
                                  {
171
23.6k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
47.5k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
23.8k
                                      sortbuf[k - 1] = sortbuf[k];
175
23.6k
                                    sortbuf_count--;
176
23.6k
                                    continue;
177
23.6k
                                  }
178
41.3k
                              }
179
125k
                            j++;
180
125k
                          }
181
10.1M
                        if (s < s_end && sortbuf_count == 1)
182
3.20M
                          {
183
3.20M
                            ucs4_t combined =
184
3.20M
                              composer (sortbuf[0].code, uc);
185
3.20M
                            if (combined)
186
9.74k
                              {
187
9.74k
                                uc = combined;
188
9.74k
                                ccc = 0;
189
                                /* uc could be further combined with subsequent
190
                                   characters.  So don't put it into sortbuf[0] in
191
                                   this round, only in the next round.  */
192
9.74k
                                sortbuf_count = 0;
193
9.74k
                              }
194
3.20M
                          }
195
10.1M
                      }
196
17.2M
                  }
197
198
27.5M
                for (size_t j = 0; j < sortbuf_count; j++)
199
10.3M
                  {
200
10.3M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
10.3M
                    if (length < allocated)
204
3.33M
                      {
205
3.33M
                        int ret =
206
3.33M
                          U_UCTOMB (result + length, muc, allocated - length);
207
3.33M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
3.33M
                        if (ret >= 0)
213
3.33M
                          {
214
3.33M
                            length += ret;
215
3.33M
                            goto done_appending;
216
3.33M
                          }
217
3.33M
                      }
218
6.97M
                    {
219
6.97M
                      size_t old_allocated = allocated;
220
6.97M
                      size_t new_allocated = 2 * old_allocated;
221
6.97M
                      if (new_allocated < 64)
222
6.97M
                        new_allocated = 64;
223
6.97M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
6.97M
                      {
226
6.97M
                        UNIT *larger_result;
227
6.97M
                        if (result == NULL)
228
6.97M
                          {
229
6.97M
                            larger_result =
230
6.97M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
6.97M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
6.97M
                          }
237
3.52k
                        else if (result == resultbuf)
238
0
                          {
239
0
                            larger_result =
240
0
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
241
0
                            if (larger_result == NULL)
242
0
                              {
243
0
                                errno = ENOMEM;
244
0
                                goto fail;
245
0
                              }
246
0
                            U_CPY (larger_result, resultbuf, length);
247
0
                          }
248
3.52k
                        else
249
3.52k
                          {
250
3.52k
                            larger_result =
251
3.52k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
3.52k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
3.52k
                          }
258
6.97M
                        result = larger_result;
259
6.97M
                        allocated = new_allocated;
260
6.97M
                        {
261
6.97M
                          int ret =
262
6.97M
                            U_UCTOMB (result + length, muc, allocated - length);
263
6.97M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
6.97M
                          if (ret < 0)
269
0
                            abort ();
270
6.97M
                          length += ret;
271
6.97M
                          goto done_appending;
272
6.97M
                        }
273
6.97M
                      }
274
6.97M
                    }
275
10.3M
                   done_appending: ;
276
10.3M
                  }
277
278
                /* sortbuf is now empty.  */
279
17.2M
                sortbuf_count = 0;
280
17.2M
              }
281
282
17.3M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
7.04M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
10.3M
            if (sortbuf_count == sortbuf_allocated)
288
924
              {
289
924
                sortbuf_allocated = 2 * sortbuf_allocated;
290
924
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
924
                struct ucs4_with_ccc *new_sortbuf =
293
924
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
924
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
924
                memcpy (new_sortbuf, sortbuf,
300
924
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
924
                if (sortbuf != sortbuf_preallocated)
302
924
                  free (sortbuf);
303
924
                sortbuf = new_sortbuf;
304
924
              }
305
10.3M
            sortbuf[sortbuf_count].code = uc;
306
10.3M
            sortbuf[sortbuf_count].ccc = ccc;
307
10.3M
            sortbuf_count++;
308
309
10.3M
            i++;
310
10.3M
          }
311
312
17.3M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
7.04M
          break;
315
316
10.3M
        s += count;
317
10.3M
      }
318
7.04M
  }
319
320
7.04M
  if (length == 0)
321
74.4k
    {
322
74.4k
      if (result == NULL)
323
74.4k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
74.4k
          result = (UNIT *) malloc (1);
326
74.4k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
74.4k
        }
332
74.4k
    }
333
6.97M
  else if (result != resultbuf && length < allocated)
334
6.97M
    {
335
      /* Shrink the allocated memory if possible.  */
336
6.97M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
6.97M
      if (memory != NULL)
338
6.97M
        result = memory;
339
6.97M
    }
340
341
7.04M
  if (sortbuf_count > 0)
342
0
    abort ();
343
7.04M
  if (sortbuf != sortbuf_preallocated)
344
7.04M
    free (sortbuf);
345
346
7.04M
  *lengthp = length;
347
7.04M
  return result;
348
349
0
 fail:
350
0
  {
351
0
    int saved_errno = errno;
352
0
    if (sortbuf != sortbuf_preallocated)
353
0
      free (sortbuf);
354
0
    if (result != resultbuf)
355
0
      free (result);
356
0
    errno = saved_errno;
357
0
  }
358
  return NULL;
359
7.04M
}