Coverage Report

Created: 2026-08-28 06:46

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
9.46M
{
22
9.46M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
9.46M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
9.46M
  UNIT *result;
27
9.46M
  size_t allocated;
28
9.46M
  if (resultbuf == NULL)
29
9.46M
    {
30
9.46M
      result = NULL;
31
9.46M
      allocated = 0;
32
9.46M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
9.46M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
9.46M
  #define SORTBUF_PREALLOCATED 64
42
9.46M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
9.46M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
9.46M
    sortbuf_preallocated;
45
9.46M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
9.46M
  size_t sortbuf_count = 0;
47
48
9.46M
  {
49
9.46M
    const UNIT *s_end = s + n;
50
51
9.46M
    for (;;)
52
31.7M
      {
53
31.7M
        int count;
54
31.7M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
31.7M
        int decomposed_count;
56
57
31.7M
        if (s < s_end)
58
22.3M
          {
59
            /* Fetch the next character.  */
60
22.3M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
22.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
54.1M
            for (int curr = 0; curr < decomposed_count; )
70
31.8M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
31.8M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
31.8M
                int curr_decomposed_count;
75
76
31.8M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
31.8M
                if (curr_decomposed_count >= 0)
78
3.17M
                  {
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.17M
                    int shift = curr_decomposed_count - 1;
83
84
3.17M
                    if (shift < 0)
85
0
                      abort ();
86
3.17M
                    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
25.9k
                          decomposed[j + shift] = decomposed[j];
93
2.83M
                      }
94
12.7M
                    for (; shift >= 0; shift--)
95
9.53M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.17M
                  }
97
28.6M
                else
98
28.6M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
28.6M
                    curr++;
101
28.6M
                  }
102
31.8M
              }
103
22.3M
          }
104
9.46M
        else
105
9.46M
          {
106
9.46M
            count = 0;
107
9.46M
            decomposed_count = 0;
108
9.46M
          }
109
110
31.7M
        int i = 0;
111
31.7M
        for (;;)
112
60.4M
          {
113
60.4M
            ucs4_t uc;
114
60.4M
            int ccc;
115
116
60.4M
            if (s < s_end)
117
50.9M
              {
118
                /* Fetch the next character from the decomposition.  */
119
50.9M
                if (i == decomposed_count)
120
22.3M
                  break;
121
28.6M
                uc = decomposed[i];
122
28.6M
                ccc = uc_combining_class (uc);
123
28.6M
              }
124
9.46M
            else
125
9.46M
              {
126
                /* End of string reached.  */
127
9.46M
                uc = 0;
128
9.46M
                ccc = 0;
129
9.46M
              }
130
131
38.1M
            if (ccc == 0)
132
34.9M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
34.9M
                if (sortbuf_count > 1)
136
1.70M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.70M
                                                           sortbuf + sortbuf_count);
138
139
34.9M
                if (composer != NULL)
140
34.9M
                  {
141
                    /* Attempt to combine decomposed characters, as specified
142
                       in the Unicode Standard Annex #15 "Unicode Normalization
143
                       Forms".  We need to check
144
                         1. whether the first accumulated character is a
145
                            "starter" (i.e. has ccc = 0).  This is usually the
146
                            case.  But when the string starts with a
147
                            non-starter, the sortbuf also starts with a
148
                            non-starter.  Btw, this check could also be
149
                            omitted, because the composition table has only
150
                            entries (code1, code2) for which code1 is a
151
                            starter; if the first accumulated character is not
152
                            a starter, no lookup will succeed.
153
                         2. If the sortbuf has more than one character, check
154
                            for each of these characters that are not "blocked"
155
                            from the starter (i.e. have a ccc that is higher
156
                            than the ccc of the previous character) whether it
157
                            can be combined with the first character.
158
                         3. If only one character is left in sortbuf, check
159
                            whether it can be combined with the next character
160
                            (also a starter).  */
161
34.9M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
25.4M
                      {
163
28.6M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.20M
                          {
165
3.20M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.73M
                              {
167
1.73M
                                ucs4_t combined =
168
1.73M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.73M
                                if (combined)
170
1.68M
                                  {
171
1.68M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.75M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.07M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.68M
                                    sortbuf_count--;
176
1.68M
                                    continue;
177
1.68M
                                  }
178
1.73M
                              }
179
1.52M
                            j++;
180
1.52M
                          }
181
25.4M
                        if (s < s_end && sortbuf_count == 1)
182
16.0M
                          {
183
16.0M
                            ucs4_t combined =
184
16.0M
                              composer (sortbuf[0].code, uc);
185
16.0M
                            if (combined)
186
15.9k
                              {
187
15.9k
                                uc = combined;
188
15.9k
                                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
15.9k
                                sortbuf_count = 0;
193
15.9k
                              }
194
16.0M
                          }
195
25.4M
                      }
196
34.9M
                  }
197
198
61.8M
                for (size_t j = 0; j < sortbuf_count; j++)
199
26.9M
                  {
200
26.9M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
26.9M
                    if (length < allocated)
204
17.5M
                      {
205
17.5M
                        int ret =
206
17.5M
                          U_UCTOMB (result + length, muc, allocated - length);
207
17.5M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
17.5M
                        if (ret >= 0)
213
17.5M
                          {
214
17.5M
                            length += ret;
215
17.5M
                            goto done_appending;
216
17.5M
                          }
217
17.5M
                      }
218
9.41M
                    {
219
9.41M
                      size_t old_allocated = allocated;
220
9.41M
                      size_t new_allocated = 2 * old_allocated;
221
9.41M
                      if (new_allocated < 64)
222
9.40M
                        new_allocated = 64;
223
9.41M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
9.41M
                      {
226
9.41M
                        UNIT *larger_result;
227
9.41M
                        if (result == NULL)
228
9.40M
                          {
229
9.40M
                            larger_result =
230
9.40M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
9.40M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
9.40M
                          }
237
15.3k
                        else if (result == resultbuf)
238
0
                          {
239
0
                            larger_result =
240
0
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
241
0
                            if (larger_result == NULL)
242
0
                              {
243
0
                                errno = ENOMEM;
244
0
                                goto fail;
245
0
                              }
246
0
                            U_CPY (larger_result, resultbuf, length);
247
0
                          }
248
15.3k
                        else
249
15.3k
                          {
250
15.3k
                            larger_result =
251
15.3k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
15.3k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
15.3k
                          }
258
9.41M
                        result = larger_result;
259
9.41M
                        allocated = new_allocated;
260
9.41M
                        {
261
9.41M
                          int ret =
262
9.41M
                            U_UCTOMB (result + length, muc, allocated - length);
263
9.41M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
9.41M
                          if (ret < 0)
269
0
                            abort ();
270
9.41M
                          length += ret;
271
9.41M
                          goto done_appending;
272
9.41M
                        }
273
9.41M
                      }
274
9.41M
                    }
275
26.9M
                   done_appending: ;
276
26.9M
                  }
277
278
                /* sortbuf is now empty.  */
279
34.9M
                sortbuf_count = 0;
280
34.9M
              }
281
282
38.1M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
9.46M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
28.6M
            if (sortbuf_count == sortbuf_allocated)
288
1.97k
              {
289
1.97k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.97k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.97k
                struct ucs4_with_ccc *new_sortbuf =
293
1.97k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.97k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.97k
                memcpy (new_sortbuf, sortbuf,
300
1.97k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.97k
                if (sortbuf != sortbuf_preallocated)
302
1.97k
                  free (sortbuf);
303
1.97k
                sortbuf = new_sortbuf;
304
1.97k
              }
305
28.6M
            sortbuf[sortbuf_count].code = uc;
306
28.6M
            sortbuf[sortbuf_count].ccc = ccc;
307
28.6M
            sortbuf_count++;
308
309
28.6M
            i++;
310
28.6M
          }
311
312
31.7M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
9.46M
          break;
315
316
22.3M
        s += count;
317
22.3M
      }
318
9.46M
  }
319
320
9.46M
  if (length == 0)
321
62.9k
    {
322
62.9k
      if (result == NULL)
323
62.9k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
62.9k
          result = (UNIT *) malloc (1);
326
62.9k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
62.9k
        }
332
62.9k
    }
333
9.40M
  else if (result != resultbuf && length < allocated)
334
9.40M
    {
335
      /* Shrink the allocated memory if possible.  */
336
9.40M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
9.40M
      if (memory != NULL)
338
9.40M
        result = memory;
339
9.40M
    }
340
341
9.46M
  if (sortbuf_count > 0)
342
0
    abort ();
343
9.46M
  if (sortbuf != sortbuf_preallocated)
344
9.46M
    free (sortbuf);
345
346
9.46M
  *lengthp = length;
347
9.46M
  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
9.46M
}
u8_normalize
Line
Count
Source
21
3.17M
{
22
3.17M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
3.17M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
3.17M
  UNIT *result;
27
3.17M
  size_t allocated;
28
3.17M
  if (resultbuf == NULL)
29
3.17M
    {
30
3.17M
      result = NULL;
31
3.17M
      allocated = 0;
32
3.17M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
3.17M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
3.17M
  #define SORTBUF_PREALLOCATED 64
42
3.17M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
3.17M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
3.17M
    sortbuf_preallocated;
45
3.17M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
3.17M
  size_t sortbuf_count = 0;
47
48
3.17M
  {
49
3.17M
    const UNIT *s_end = s + n;
50
51
3.17M
    for (;;)
52
16.4M
      {
53
16.4M
        int count;
54
16.4M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
16.4M
        int decomposed_count;
56
57
16.4M
        if (s < s_end)
58
13.2M
          {
59
            /* Fetch the next character.  */
60
13.2M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
13.2M
            decomposed_count = 1;
62
63
            /* Decompose it, recursively.
64
               It would be possible to precompute the recursive decomposition
65
               and store it in a table.  But this would significantly increase
66
               the size of the decomposition tables, because for example for
67
               U+1FC1 the recursive canonical decomposition and the recursive
68
               compatibility decomposition are different.  */
69
36.0M
            for (int curr = 0; curr < decomposed_count; )
70
22.7M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
22.7M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
22.7M
                int curr_decomposed_count;
75
76
22.7M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
22.7M
                if (curr_decomposed_count >= 0)
78
3.14M
                  {
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.14M
                    int shift = curr_decomposed_count - 1;
83
84
3.14M
                    if (shift < 0)
85
0
                      abort ();
86
3.14M
                    if (shift > 0)
87
2.80M
                      {
88
2.80M
                        decomposed_count += shift;
89
2.80M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.81M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
16.5k
                          decomposed[j + shift] = decomposed[j];
93
2.80M
                      }
94
12.6M
                    for (; shift >= 0; shift--)
95
9.47M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
3.14M
                  }
97
19.6M
                else
98
19.6M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
19.6M
                    curr++;
101
19.6M
                  }
102
22.7M
              }
103
13.2M
          }
104
3.17M
        else
105
3.17M
          {
106
3.17M
            count = 0;
107
3.17M
            decomposed_count = 0;
108
3.17M
          }
109
110
16.4M
        int i = 0;
111
16.4M
        for (;;)
112
36.0M
          {
113
36.0M
            ucs4_t uc;
114
36.0M
            int ccc;
115
116
36.0M
            if (s < s_end)
117
32.8M
              {
118
                /* Fetch the next character from the decomposition.  */
119
32.8M
                if (i == decomposed_count)
120
13.2M
                  break;
121
19.6M
                uc = decomposed[i];
122
19.6M
                ccc = uc_combining_class (uc);
123
19.6M
              }
124
3.17M
            else
125
3.17M
              {
126
                /* End of string reached.  */
127
3.17M
                uc = 0;
128
3.17M
                ccc = 0;
129
3.17M
              }
130
131
22.7M
            if (ccc == 0)
132
19.6M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
19.6M
                if (sortbuf_count > 1)
136
1.68M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.68M
                                                           sortbuf + sortbuf_count);
138
139
19.6M
                if (composer != NULL)
140
19.6M
                  {
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
19.6M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
16.4M
                      {
163
19.5M
                        for (size_t j = 1; j < sortbuf_count; )
164
3.10M
                          {
165
3.10M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.70M
                              {
167
1.70M
                                ucs4_t combined =
168
1.70M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.70M
                                if (combined)
170
1.66M
                                  {
171
1.66M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.72M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
2.05M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.66M
                                    sortbuf_count--;
176
1.66M
                                    continue;
177
1.66M
                                  }
178
1.70M
                              }
179
1.44M
                            j++;
180
1.44M
                          }
181
16.4M
                        if (s < s_end && sortbuf_count == 1)
182
13.2M
                          {
183
13.2M
                            ucs4_t combined =
184
13.2M
                              composer (sortbuf[0].code, uc);
185
13.2M
                            if (combined)
186
7.44k
                              {
187
7.44k
                                uc = combined;
188
7.44k
                                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.44k
                                sortbuf_count = 0;
193
7.44k
                              }
194
13.2M
                          }
195
16.4M
                      }
196
19.6M
                  }
197
198
37.5M
                for (size_t j = 0; j < sortbuf_count; j++)
199
17.9M
                  {
200
17.9M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
17.9M
                    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.18M
                    {
219
3.18M
                      size_t old_allocated = allocated;
220
3.18M
                      size_t new_allocated = 2 * old_allocated;
221
3.18M
                      if (new_allocated < 64)
222
3.17M
                        new_allocated = 64;
223
3.18M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
3.18M
                      {
226
3.18M
                        UNIT *larger_result;
227
3.18M
                        if (result == NULL)
228
3.17M
                          {
229
3.17M
                            larger_result =
230
3.17M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
3.17M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
3.17M
                          }
237
12.4k
                        else if (result == resultbuf)
238
0
                          {
239
0
                            larger_result =
240
0
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
241
0
                            if (larger_result == NULL)
242
0
                              {
243
0
                                errno = ENOMEM;
244
0
                                goto fail;
245
0
                              }
246
0
                            U_CPY (larger_result, resultbuf, length);
247
0
                          }
248
12.4k
                        else
249
12.4k
                          {
250
12.4k
                            larger_result =
251
12.4k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
12.4k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
12.4k
                          }
258
3.18M
                        result = larger_result;
259
3.18M
                        allocated = new_allocated;
260
3.18M
                        {
261
3.18M
                          int ret =
262
3.18M
                            U_UCTOMB (result + length, muc, allocated - length);
263
3.18M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
3.18M
                          if (ret < 0)
269
0
                            abort ();
270
3.18M
                          length += ret;
271
3.18M
                          goto done_appending;
272
3.18M
                        }
273
3.18M
                      }
274
3.18M
                    }
275
17.9M
                   done_appending: ;
276
17.9M
                  }
277
278
                /* sortbuf is now empty.  */
279
19.6M
                sortbuf_count = 0;
280
19.6M
              }
281
282
22.7M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
3.17M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
19.6M
            if (sortbuf_count == sortbuf_allocated)
288
1.15k
              {
289
1.15k
                sortbuf_allocated = 2 * sortbuf_allocated;
290
1.15k
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
1.15k
                struct ucs4_with_ccc *new_sortbuf =
293
1.15k
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
1.15k
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
1.15k
                memcpy (new_sortbuf, sortbuf,
300
1.15k
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
1.15k
                if (sortbuf != sortbuf_preallocated)
302
1.15k
                  free (sortbuf);
303
1.15k
                sortbuf = new_sortbuf;
304
1.15k
              }
305
19.6M
            sortbuf[sortbuf_count].code = uc;
306
19.6M
            sortbuf[sortbuf_count].ccc = ccc;
307
19.6M
            sortbuf_count++;
308
309
19.6M
            i++;
310
19.6M
          }
311
312
16.4M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
3.17M
          break;
315
316
13.2M
        s += count;
317
13.2M
      }
318
3.17M
  }
319
320
3.17M
  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.17M
  else if (result != resultbuf && length < allocated)
334
3.17M
    {
335
      /* Shrink the allocated memory if possible.  */
336
3.17M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
3.17M
      if (memory != NULL)
338
3.17M
        result = memory;
339
3.17M
    }
340
341
3.17M
  if (sortbuf_count > 0)
342
0
    abort ();
343
3.17M
  if (sortbuf != sortbuf_preallocated)
344
3.17M
    free (sortbuf);
345
346
3.17M
  *lengthp = length;
347
3.17M
  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.17M
}
u32_normalize
Line
Count
Source
21
6.29M
{
22
6.29M
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
6.29M
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
6.29M
  UNIT *result;
27
6.29M
  size_t allocated;
28
6.29M
  if (resultbuf == NULL)
29
6.29M
    {
30
6.29M
      result = NULL;
31
6.29M
      allocated = 0;
32
6.29M
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
6.29M
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
6.29M
  #define SORTBUF_PREALLOCATED 64
42
6.29M
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
6.29M
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
6.29M
    sortbuf_preallocated;
45
6.29M
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
6.29M
  size_t sortbuf_count = 0;
47
48
6.29M
  {
49
6.29M
    const UNIT *s_end = s + n;
50
51
6.29M
    for (;;)
52
15.3M
      {
53
15.3M
        int count;
54
15.3M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
15.3M
        int decomposed_count;
56
57
15.3M
        if (s < s_end)
58
9.04M
          {
59
            /* Fetch the next character.  */
60
9.04M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
9.04M
            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
18.1M
            for (int curr = 0; curr < decomposed_count; )
70
9.10M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
9.10M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
9.10M
                int curr_decomposed_count;
75
76
9.10M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
9.10M
                if (curr_decomposed_count >= 0)
78
29.9k
                  {
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
29.9k
                    int shift = curr_decomposed_count - 1;
83
84
29.9k
                    if (shift < 0)
85
0
                      abort ();
86
29.9k
                    if (shift > 0)
87
29.7k
                      {
88
29.7k
                        decomposed_count += shift;
89
29.7k
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
39.0k
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
9.33k
                          decomposed[j + shift] = decomposed[j];
93
29.7k
                      }
94
89.5k
                    for (; shift >= 0; shift--)
95
59.6k
                      decomposed[curr + shift] = curr_decomposed[shift];
96
29.9k
                  }
97
9.07M
                else
98
9.07M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
9.07M
                    curr++;
101
9.07M
                  }
102
9.10M
              }
103
9.04M
          }
104
6.29M
        else
105
6.29M
          {
106
6.29M
            count = 0;
107
6.29M
            decomposed_count = 0;
108
6.29M
          }
109
110
15.3M
        int i = 0;
111
15.3M
        for (;;)
112
24.4M
          {
113
24.4M
            ucs4_t uc;
114
24.4M
            int ccc;
115
116
24.4M
            if (s < s_end)
117
18.1M
              {
118
                /* Fetch the next character from the decomposition.  */
119
18.1M
                if (i == decomposed_count)
120
9.04M
                  break;
121
9.07M
                uc = decomposed[i];
122
9.07M
                ccc = uc_combining_class (uc);
123
9.07M
              }
124
6.29M
            else
125
6.29M
              {
126
                /* End of string reached.  */
127
6.29M
                uc = 0;
128
6.29M
                ccc = 0;
129
6.29M
              }
130
131
15.3M
            if (ccc == 0)
132
15.2M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
15.2M
                if (sortbuf_count > 1)
136
22.4k
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
22.4k
                                                           sortbuf + sortbuf_count);
138
139
15.2M
                if (composer != NULL)
140
15.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
15.2M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
8.96M
                      {
163
9.06M
                        for (size_t j = 1; j < sortbuf_count; )
164
95.9k
                          {
165
95.9k
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
32.9k
                              {
167
32.9k
                                ucs4_t combined =
168
32.9k
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
32.9k
                                if (combined)
170
19.5k
                                  {
171
19.5k
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
33.0k
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
13.5k
                                      sortbuf[k - 1] = sortbuf[k];
175
19.5k
                                    sortbuf_count--;
176
19.5k
                                    continue;
177
19.5k
                                  }
178
32.9k
                              }
179
76.4k
                            j++;
180
76.4k
                          }
181
8.96M
                        if (s < s_end && sortbuf_count == 1)
182
2.73M
                          {
183
2.73M
                            ucs4_t combined =
184
2.73M
                              composer (sortbuf[0].code, uc);
185
2.73M
                            if (combined)
186
8.53k
                              {
187
8.53k
                                uc = combined;
188
8.53k
                                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.53k
                                sortbuf_count = 0;
193
8.53k
                              }
194
2.73M
                          }
195
8.96M
                      }
196
15.2M
                  }
197
198
24.3M
                for (size_t j = 0; j < sortbuf_count; j++)
199
9.04M
                  {
200
9.04M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
9.04M
                    if (length < allocated)
204
2.81M
                      {
205
2.81M
                        int ret =
206
2.81M
                          U_UCTOMB (result + length, muc, allocated - length);
207
2.81M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
2.81M
                        if (ret >= 0)
213
2.81M
                          {
214
2.81M
                            length += ret;
215
2.81M
                            goto done_appending;
216
2.81M
                          }
217
2.81M
                      }
218
6.23M
                    {
219
6.23M
                      size_t old_allocated = allocated;
220
6.23M
                      size_t new_allocated = 2 * old_allocated;
221
6.23M
                      if (new_allocated < 64)
222
6.22M
                        new_allocated = 64;
223
6.23M
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
6.23M
                      {
226
6.23M
                        UNIT *larger_result;
227
6.23M
                        if (result == NULL)
228
6.22M
                          {
229
6.22M
                            larger_result =
230
6.22M
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
6.22M
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
6.22M
                          }
237
2.86k
                        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.86k
                        else
249
2.86k
                          {
250
2.86k
                            larger_result =
251
2.86k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
2.86k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
2.86k
                          }
258
6.23M
                        result = larger_result;
259
6.23M
                        allocated = new_allocated;
260
6.23M
                        {
261
6.23M
                          int ret =
262
6.23M
                            U_UCTOMB (result + length, muc, allocated - length);
263
6.23M
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
6.23M
                          if (ret < 0)
269
0
                            abort ();
270
6.23M
                          length += ret;
271
6.23M
                          goto done_appending;
272
6.23M
                        }
273
6.23M
                      }
274
6.23M
                    }
275
9.04M
                   done_appending: ;
276
9.04M
                  }
277
278
                /* sortbuf is now empty.  */
279
15.2M
                sortbuf_count = 0;
280
15.2M
              }
281
282
15.3M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
6.29M
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
9.07M
            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
9.07M
            sortbuf[sortbuf_count].code = uc;
306
9.07M
            sortbuf[sortbuf_count].ccc = ccc;
307
9.07M
            sortbuf_count++;
308
309
9.07M
            i++;
310
9.07M
          }
311
312
15.3M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
6.29M
          break;
315
316
9.04M
        s += count;
317
9.04M
      }
318
6.29M
  }
319
320
6.29M
  if (length == 0)
321
62.9k
    {
322
62.9k
      if (result == NULL)
323
62.9k
        {
324
          /* Return a non-NULL value.  NULL means error.  */
325
62.9k
          result = (UNIT *) malloc (1);
326
62.9k
          if (result == NULL)
327
0
            {
328
0
              errno = ENOMEM;
329
0
              goto fail;
330
0
            }
331
62.9k
        }
332
62.9k
    }
333
6.22M
  else if (result != resultbuf && length < allocated)
334
6.22M
    {
335
      /* Shrink the allocated memory if possible.  */
336
6.22M
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
6.22M
      if (memory != NULL)
338
6.22M
        result = memory;
339
6.22M
    }
340
341
6.29M
  if (sortbuf_count > 0)
342
0
    abort ();
343
6.29M
  if (sortbuf != sortbuf_preallocated)
344
6.29M
    free (sortbuf);
345
346
6.29M
  *lengthp = length;
347
6.29M
  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.29M
}