Coverage Report

Created: 2026-06-26 07:19

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
6.99k
{
22
6.99k
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
6.99k
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
6.99k
  UNIT *result;
27
6.99k
  size_t allocated;
28
6.99k
  if (resultbuf == NULL)
29
6.99k
    {
30
6.99k
      result = NULL;
31
6.99k
      allocated = 0;
32
6.99k
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
6.99k
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
6.99k
  #define SORTBUF_PREALLOCATED 64
42
6.99k
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
6.99k
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
6.99k
    sortbuf_preallocated;
45
6.99k
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
6.99k
  size_t sortbuf_count = 0;
47
48
6.99k
  {
49
6.99k
    const UNIT *s_end = s + n;
50
51
6.99k
    for (;;)
52
5.55M
      {
53
5.55M
        int count;
54
5.55M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
5.55M
        int decomposed_count;
56
57
5.55M
        if (s < s_end)
58
5.55M
          {
59
            /* Fetch the next character.  */
60
5.55M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
5.55M
            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
19.7M
            for (int curr = 0; curr < decomposed_count; )
70
14.2M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
14.2M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
14.2M
                int curr_decomposed_count;
75
76
14.2M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
14.2M
                if (curr_decomposed_count >= 0)
78
2.61M
                  {
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
2.61M
                    int shift = curr_decomposed_count - 1;
83
84
2.61M
                    if (shift < 0)
85
0
                      abort ();
86
2.61M
                    if (shift > 0)
87
2.38M
                      {
88
2.38M
                        decomposed_count += shift;
89
2.38M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.39M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
10.9k
                          decomposed[j + shift] = decomposed[j];
93
2.38M
                      }
94
11.2M
                    for (; shift >= 0; shift--)
95
8.65M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
2.61M
                  }
97
11.5M
                else
98
11.5M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
11.5M
                    curr++;
101
11.5M
                  }
102
14.2M
              }
103
5.55M
          }
104
6.99k
        else
105
6.99k
          {
106
6.99k
            count = 0;
107
6.99k
            decomposed_count = 0;
108
6.99k
          }
109
110
5.55M
        int i = 0;
111
5.55M
        for (;;)
112
17.1M
          {
113
17.1M
            ucs4_t uc;
114
17.1M
            int ccc;
115
116
17.1M
            if (s < s_end)
117
17.1M
              {
118
                /* Fetch the next character from the decomposition.  */
119
17.1M
                if (i == decomposed_count)
120
5.55M
                  break;
121
11.5M
                uc = decomposed[i];
122
11.5M
                ccc = uc_combining_class (uc);
123
11.5M
              }
124
6.99k
            else
125
6.99k
              {
126
                /* End of string reached.  */
127
6.99k
                uc = 0;
128
6.99k
                ccc = 0;
129
6.99k
              }
130
131
11.5M
            if (ccc == 0)
132
8.89M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
8.89M
                if (sortbuf_count > 1)
136
1.46M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.46M
                                                           sortbuf + sortbuf_count);
138
139
8.89M
                if (composer != NULL)
140
8.89M
                  {
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
8.89M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
8.88M
                      {
163
11.5M
                        for (size_t j = 1; j < sortbuf_count; )
164
2.68M
                          {
165
2.68M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.47M
                              {
167
1.47M
                                ucs4_t combined =
168
1.47M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.47M
                                if (combined)
170
1.44M
                                  {
171
1.44M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.19M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
1.74M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.44M
                                    sortbuf_count--;
176
1.44M
                                    continue;
177
1.44M
                                  }
178
1.47M
                              }
179
1.23M
                            j++;
180
1.23M
                          }
181
8.88M
                        if (s < s_end && sortbuf_count == 1)
182
8.86M
                          {
183
8.86M
                            ucs4_t combined =
184
8.86M
                              composer (sortbuf[0].code, uc);
185
8.86M
                            if (combined)
186
4.23k
                              {
187
4.23k
                                uc = combined;
188
4.23k
                                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
4.23k
                                sortbuf_count = 0;
193
4.23k
                              }
194
8.86M
                          }
195
8.88M
                      }
196
8.89M
                  }
197
198
19.0M
                for (size_t j = 0; j < sortbuf_count; j++)
199
10.1M
                  {
200
10.1M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
10.1M
                    if (length < allocated)
204
10.1M
                      {
205
10.1M
                        int ret =
206
10.1M
                          U_UCTOMB (result + length, muc, allocated - length);
207
10.1M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
10.1M
                        if (ret >= 0)
213
10.1M
                          {
214
10.1M
                            length += ret;
215
10.1M
                            goto done_appending;
216
10.1M
                          }
217
10.1M
                      }
218
14.2k
                    {
219
14.2k
                      size_t old_allocated = allocated;
220
14.2k
                      size_t new_allocated = 2 * old_allocated;
221
14.2k
                      if (new_allocated < 64)
222
6.99k
                        new_allocated = 64;
223
14.2k
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
14.2k
                      {
226
14.2k
                        UNIT *larger_result;
227
14.2k
                        if (result == NULL)
228
6.99k
                          {
229
6.99k
                            larger_result =
230
6.99k
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
6.99k
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
6.99k
                          }
237
7.22k
                        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
7.22k
                        else
249
7.22k
                          {
250
7.22k
                            larger_result =
251
7.22k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
7.22k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
7.22k
                          }
258
14.2k
                        result = larger_result;
259
14.2k
                        allocated = new_allocated;
260
14.2k
                        {
261
14.2k
                          int ret =
262
14.2k
                            U_UCTOMB (result + length, muc, allocated - length);
263
14.2k
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
14.2k
                          if (ret < 0)
269
0
                            abort ();
270
14.2k
                          length += ret;
271
14.2k
                          goto done_appending;
272
14.2k
                        }
273
14.2k
                      }
274
14.2k
                    }
275
10.1M
                   done_appending: ;
276
10.1M
                  }
277
278
                /* sortbuf is now empty.  */
279
8.89M
                sortbuf_count = 0;
280
8.89M
              }
281
282
11.5M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
6.99k
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
11.5M
            if (sortbuf_count == sortbuf_allocated)
288
810
              {
289
810
                sortbuf_allocated = 2 * sortbuf_allocated;
290
810
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
810
                struct ucs4_with_ccc *new_sortbuf =
293
810
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
810
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
810
                memcpy (new_sortbuf, sortbuf,
300
810
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
810
                if (sortbuf != sortbuf_preallocated)
302
810
                  free (sortbuf);
303
810
                sortbuf = new_sortbuf;
304
810
              }
305
11.5M
            sortbuf[sortbuf_count].code = uc;
306
11.5M
            sortbuf[sortbuf_count].ccc = ccc;
307
11.5M
            sortbuf_count++;
308
309
11.5M
            i++;
310
11.5M
          }
311
312
5.55M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
6.99k
          break;
315
316
5.55M
        s += count;
317
5.55M
      }
318
6.99k
  }
319
320
6.99k
  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
6.99k
  else if (result != resultbuf && length < allocated)
334
6.94k
    {
335
      /* Shrink the allocated memory if possible.  */
336
6.94k
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
6.94k
      if (memory != NULL)
338
6.94k
        result = memory;
339
6.94k
    }
340
341
6.99k
  if (sortbuf_count > 0)
342
0
    abort ();
343
6.99k
  if (sortbuf != sortbuf_preallocated)
344
6.99k
    free (sortbuf);
345
346
6.99k
  *lengthp = length;
347
6.99k
  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.99k
}
u8_normalize
Line
Count
Source
21
6.62k
{
22
6.62k
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
6.62k
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
6.62k
  UNIT *result;
27
6.62k
  size_t allocated;
28
6.62k
  if (resultbuf == NULL)
29
6.62k
    {
30
6.62k
      result = NULL;
31
6.62k
      allocated = 0;
32
6.62k
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
6.62k
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
6.62k
  #define SORTBUF_PREALLOCATED 64
42
6.62k
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
6.62k
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
6.62k
    sortbuf_preallocated;
45
6.62k
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
6.62k
  size_t sortbuf_count = 0;
47
48
6.62k
  {
49
6.62k
    const UNIT *s_end = s + n;
50
51
6.62k
    for (;;)
52
5.55M
      {
53
5.55M
        int count;
54
5.55M
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
5.55M
        int decomposed_count;
56
57
5.55M
        if (s < s_end)
58
5.55M
          {
59
            /* Fetch the next character.  */
60
5.55M
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
5.55M
            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
19.7M
            for (int curr = 0; curr < decomposed_count; )
70
14.2M
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
14.2M
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
14.2M
                int curr_decomposed_count;
75
76
14.2M
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
14.2M
                if (curr_decomposed_count >= 0)
78
2.61M
                  {
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
2.61M
                    int shift = curr_decomposed_count - 1;
83
84
2.61M
                    if (shift < 0)
85
0
                      abort ();
86
2.61M
                    if (shift > 0)
87
2.38M
                      {
88
2.38M
                        decomposed_count += shift;
89
2.38M
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
2.39M
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
10.9k
                          decomposed[j + shift] = decomposed[j];
93
2.38M
                      }
94
11.2M
                    for (; shift >= 0; shift--)
95
8.65M
                      decomposed[curr + shift] = curr_decomposed[shift];
96
2.61M
                  }
97
11.5M
                else
98
11.5M
                  {
99
                    /* decomposed[curr] is atomic.  */
100
11.5M
                    curr++;
101
11.5M
                  }
102
14.2M
              }
103
5.55M
          }
104
6.62k
        else
105
6.62k
          {
106
6.62k
            count = 0;
107
6.62k
            decomposed_count = 0;
108
6.62k
          }
109
110
5.55M
        int i = 0;
111
5.55M
        for (;;)
112
17.1M
          {
113
17.1M
            ucs4_t uc;
114
17.1M
            int ccc;
115
116
17.1M
            if (s < s_end)
117
17.1M
              {
118
                /* Fetch the next character from the decomposition.  */
119
17.1M
                if (i == decomposed_count)
120
5.55M
                  break;
121
11.5M
                uc = decomposed[i];
122
11.5M
                ccc = uc_combining_class (uc);
123
11.5M
              }
124
6.62k
            else
125
6.62k
              {
126
                /* End of string reached.  */
127
6.62k
                uc = 0;
128
6.62k
                ccc = 0;
129
6.62k
              }
130
131
11.5M
            if (ccc == 0)
132
8.89M
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
8.89M
                if (sortbuf_count > 1)
136
1.45M
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
1.45M
                                                           sortbuf + sortbuf_count);
138
139
8.89M
                if (composer != NULL)
140
8.89M
                  {
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
8.89M
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
8.88M
                      {
163
11.5M
                        for (size_t j = 1; j < sortbuf_count; )
164
2.68M
                          {
165
2.68M
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
1.47M
                              {
167
1.47M
                                ucs4_t combined =
168
1.47M
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
1.47M
                                if (combined)
170
1.44M
                                  {
171
1.44M
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
3.19M
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
1.74M
                                      sortbuf[k - 1] = sortbuf[k];
175
1.44M
                                    sortbuf_count--;
176
1.44M
                                    continue;
177
1.44M
                                  }
178
1.47M
                              }
179
1.23M
                            j++;
180
1.23M
                          }
181
8.88M
                        if (s < s_end && sortbuf_count == 1)
182
8.86M
                          {
183
8.86M
                            ucs4_t combined =
184
8.86M
                              composer (sortbuf[0].code, uc);
185
8.86M
                            if (combined)
186
4.23k
                              {
187
4.23k
                                uc = combined;
188
4.23k
                                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
4.23k
                                sortbuf_count = 0;
193
4.23k
                              }
194
8.86M
                          }
195
8.88M
                      }
196
8.89M
                  }
197
198
19.0M
                for (size_t j = 0; j < sortbuf_count; j++)
199
10.1M
                  {
200
10.1M
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
10.1M
                    if (length < allocated)
204
10.1M
                      {
205
10.1M
                        int ret =
206
10.1M
                          U_UCTOMB (result + length, muc, allocated - length);
207
10.1M
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
10.1M
                        if (ret >= 0)
213
10.1M
                          {
214
10.1M
                            length += ret;
215
10.1M
                            goto done_appending;
216
10.1M
                          }
217
10.1M
                      }
218
13.8k
                    {
219
13.8k
                      size_t old_allocated = allocated;
220
13.8k
                      size_t new_allocated = 2 * old_allocated;
221
13.8k
                      if (new_allocated < 64)
222
6.62k
                        new_allocated = 64;
223
13.8k
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
13.8k
                      {
226
13.8k
                        UNIT *larger_result;
227
13.8k
                        if (result == NULL)
228
6.62k
                          {
229
6.62k
                            larger_result =
230
6.62k
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
6.62k
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
6.62k
                          }
237
7.22k
                        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
7.22k
                        else
249
7.22k
                          {
250
7.22k
                            larger_result =
251
7.22k
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
7.22k
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
7.22k
                          }
258
13.8k
                        result = larger_result;
259
13.8k
                        allocated = new_allocated;
260
13.8k
                        {
261
13.8k
                          int ret =
262
13.8k
                            U_UCTOMB (result + length, muc, allocated - length);
263
13.8k
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
13.8k
                          if (ret < 0)
269
0
                            abort ();
270
13.8k
                          length += ret;
271
13.8k
                          goto done_appending;
272
13.8k
                        }
273
13.8k
                      }
274
13.8k
                    }
275
10.1M
                   done_appending: ;
276
10.1M
                  }
277
278
                /* sortbuf is now empty.  */
279
8.89M
                sortbuf_count = 0;
280
8.89M
              }
281
282
11.5M
            if (!(s < s_end))
283
              /* End of string reached.  */
284
6.62k
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
11.5M
            if (sortbuf_count == sortbuf_allocated)
288
810
              {
289
810
                sortbuf_allocated = 2 * sortbuf_allocated;
290
810
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
810
                struct ucs4_with_ccc *new_sortbuf =
293
810
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
810
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
810
                memcpy (new_sortbuf, sortbuf,
300
810
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
810
                if (sortbuf != sortbuf_preallocated)
302
810
                  free (sortbuf);
303
810
                sortbuf = new_sortbuf;
304
810
              }
305
11.5M
            sortbuf[sortbuf_count].code = uc;
306
11.5M
            sortbuf[sortbuf_count].ccc = ccc;
307
11.5M
            sortbuf_count++;
308
309
11.5M
            i++;
310
11.5M
          }
311
312
5.55M
        if (!(s < s_end))
313
          /* End of string reached.  */
314
6.62k
          break;
315
316
5.55M
        s += count;
317
5.55M
      }
318
6.62k
  }
319
320
6.62k
  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
6.62k
  else if (result != resultbuf && length < allocated)
334
6.57k
    {
335
      /* Shrink the allocated memory if possible.  */
336
6.57k
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
6.57k
      if (memory != NULL)
338
6.57k
        result = memory;
339
6.57k
    }
340
341
6.62k
  if (sortbuf_count > 0)
342
0
    abort ();
343
6.62k
  if (sortbuf != sortbuf_preallocated)
344
6.62k
    free (sortbuf);
345
346
6.62k
  *lengthp = length;
347
6.62k
  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.62k
}
u32_normalize
Line
Count
Source
21
372
{
22
372
  int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer;
23
372
  ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer;
24
25
  /* The result being accumulated.  */
26
372
  UNIT *result;
27
372
  size_t allocated;
28
372
  if (resultbuf == NULL)
29
372
    {
30
372
      result = NULL;
31
372
      allocated = 0;
32
372
    }
33
0
  else
34
0
    {
35
0
      result = resultbuf;
36
0
      allocated = *lengthp;
37
0
    }
38
372
  size_t length = 0;
39
40
  /* The buffer for sorting.  */
41
372
  #define SORTBUF_PREALLOCATED 64
42
372
  struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED];
43
372
  struct ucs4_with_ccc *sortbuf = /* array of size 2 * sortbuf_allocated */
44
372
    sortbuf_preallocated;
45
372
  size_t sortbuf_allocated = SORTBUF_PREALLOCATED;
46
372
  size_t sortbuf_count = 0;
47
48
372
  {
49
372
    const UNIT *s_end = s + n;
50
51
372
    for (;;)
52
1.39k
      {
53
1.39k
        int count;
54
1.39k
        ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH];
55
1.39k
        int decomposed_count;
56
57
1.39k
        if (s < s_end)
58
1.02k
          {
59
            /* Fetch the next character.  */
60
1.02k
            count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s);
61
1.02k
            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
2.60k
            for (int curr = 0; curr < decomposed_count; )
70
1.58k
              {
71
                /* Invariant: decomposed[0..curr-1] is fully decomposed, i.e.
72
                   all elements are atomic.  */
73
1.58k
                ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH];
74
1.58k
                int curr_decomposed_count;
75
76
1.58k
                curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed);
77
1.58k
                if (curr_decomposed_count >= 0)
78
279
                  {
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
279
                    int shift = curr_decomposed_count - 1;
83
84
279
                    if (shift < 0)
85
0
                      abort ();
86
279
                    if (shift > 0)
87
279
                      {
88
279
                        decomposed_count += shift;
89
279
                        if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH)
90
0
                          abort ();
91
279
                        for (int j = decomposed_count - 1 - shift; j > curr; j--)
92
0
                          decomposed[j + shift] = decomposed[j];
93
279
                      }
94
837
                    for (; shift >= 0; shift--)
95
558
                      decomposed[curr + shift] = curr_decomposed[shift];
96
279
                  }
97
1.30k
                else
98
1.30k
                  {
99
                    /* decomposed[curr] is atomic.  */
100
1.30k
                    curr++;
101
1.30k
                  }
102
1.58k
              }
103
1.02k
          }
104
372
        else
105
372
          {
106
372
            count = 0;
107
372
            decomposed_count = 0;
108
372
          }
109
110
1.39k
        int i = 0;
111
1.39k
        for (;;)
112
2.69k
          {
113
2.69k
            ucs4_t uc;
114
2.69k
            int ccc;
115
116
2.69k
            if (s < s_end)
117
2.32k
              {
118
                /* Fetch the next character from the decomposition.  */
119
2.32k
                if (i == decomposed_count)
120
1.02k
                  break;
121
1.30k
                uc = decomposed[i];
122
1.30k
                ccc = uc_combining_class (uc);
123
1.30k
              }
124
372
            else
125
372
              {
126
                /* End of string reached.  */
127
372
                uc = 0;
128
372
                ccc = 0;
129
372
              }
130
131
1.67k
            if (ccc == 0)
132
1.39k
              {
133
                /* Apply the canonical ordering algorithm to the accumulated
134
                   sequence of characters.  */
135
1.39k
                if (sortbuf_count > 1)
136
279
                  gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count,
137
279
                                                           sortbuf + sortbuf_count);
138
139
1.39k
                if (composer != NULL)
140
1.39k
                  {
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
1.39k
                    if (sortbuf_count > 0 && sortbuf[0].ccc == 0)
162
1.02k
                      {
163
1.30k
                        for (size_t j = 1; j < sortbuf_count; )
164
279
                          {
165
279
                            if (sortbuf[j].ccc > sortbuf[j - 1].ccc)
166
279
                              {
167
279
                                ucs4_t combined =
168
279
                                  composer (sortbuf[0].code, sortbuf[j].code);
169
279
                                if (combined)
170
279
                                  {
171
279
                                    sortbuf[0].code = combined;
172
                                    /* sortbuf[0].ccc = 0, still valid.  */
173
279
                                    for (size_t k = j + 1; k < sortbuf_count; k++)
174
0
                                      sortbuf[k - 1] = sortbuf[k];
175
279
                                    sortbuf_count--;
176
279
                                    continue;
177
279
                                  }
178
279
                              }
179
0
                            j++;
180
0
                          }
181
1.02k
                        if (s < s_end && sortbuf_count == 1)
182
651
                          {
183
651
                            ucs4_t combined =
184
651
                              composer (sortbuf[0].code, uc);
185
651
                            if (combined)
186
0
                              {
187
0
                                uc = combined;
188
0
                                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
0
                                sortbuf_count = 0;
193
0
                              }
194
651
                          }
195
1.02k
                      }
196
1.39k
                  }
197
198
2.41k
                for (size_t j = 0; j < sortbuf_count; j++)
199
1.02k
                  {
200
1.02k
                    ucs4_t muc = sortbuf[j].code;
201
202
                    /* Append muc to the result accumulator.  */
203
1.02k
                    if (length < allocated)
204
651
                      {
205
651
                        int ret =
206
651
                          U_UCTOMB (result + length, muc, allocated - length);
207
651
                        if (ret == -1)
208
0
                          {
209
0
                            errno = EINVAL;
210
0
                            goto fail;
211
0
                          }
212
651
                        if (ret >= 0)
213
651
                          {
214
651
                            length += ret;
215
651
                            goto done_appending;
216
651
                          }
217
651
                      }
218
372
                    {
219
372
                      size_t old_allocated = allocated;
220
372
                      size_t new_allocated = 2 * old_allocated;
221
372
                      if (new_allocated < 64)
222
372
                        new_allocated = 64;
223
372
                      if (new_allocated < old_allocated) /* integer overflow? */
224
0
                        abort ();
225
372
                      {
226
372
                        UNIT *larger_result;
227
372
                        if (result == NULL)
228
372
                          {
229
372
                            larger_result =
230
372
                              (UNIT *) malloc (new_allocated * sizeof (UNIT));
231
372
                            if (larger_result == NULL)
232
0
                              {
233
0
                                errno = ENOMEM;
234
0
                                goto fail;
235
0
                              }
236
372
                          }
237
0
                        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
0
                        else
249
0
                          {
250
0
                            larger_result =
251
0
                              (UNIT *) realloc (result, new_allocated * sizeof (UNIT));
252
0
                            if (larger_result == NULL)
253
0
                              {
254
0
                                errno = ENOMEM;
255
0
                                goto fail;
256
0
                              }
257
0
                          }
258
372
                        result = larger_result;
259
372
                        allocated = new_allocated;
260
372
                        {
261
372
                          int ret =
262
372
                            U_UCTOMB (result + length, muc, allocated - length);
263
372
                          if (ret == -1)
264
0
                            {
265
0
                              errno = EINVAL;
266
0
                              goto fail;
267
0
                            }
268
372
                          if (ret < 0)
269
0
                            abort ();
270
372
                          length += ret;
271
372
                          goto done_appending;
272
372
                        }
273
372
                      }
274
372
                    }
275
1.02k
                   done_appending: ;
276
1.02k
                  }
277
278
                /* sortbuf is now empty.  */
279
1.39k
                sortbuf_count = 0;
280
1.39k
              }
281
282
1.67k
            if (!(s < s_end))
283
              /* End of string reached.  */
284
372
              break;
285
286
            /* Append (uc, ccc) to sortbuf.  */
287
1.30k
            if (sortbuf_count == sortbuf_allocated)
288
0
              {
289
0
                sortbuf_allocated = 2 * sortbuf_allocated;
290
0
                if (sortbuf_allocated < sortbuf_count) /* integer overflow? */
291
0
                  abort ();
292
0
                struct ucs4_with_ccc *new_sortbuf =
293
0
                  (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc));
294
0
                if (new_sortbuf == NULL)
295
0
                  {
296
0
                    errno = ENOMEM;
297
0
                    goto fail;
298
0
                  }
299
0
                memcpy (new_sortbuf, sortbuf,
300
0
                        sortbuf_count * sizeof (struct ucs4_with_ccc));
301
0
                if (sortbuf != sortbuf_preallocated)
302
0
                  free (sortbuf);
303
0
                sortbuf = new_sortbuf;
304
0
              }
305
1.30k
            sortbuf[sortbuf_count].code = uc;
306
1.30k
            sortbuf[sortbuf_count].ccc = ccc;
307
1.30k
            sortbuf_count++;
308
309
1.30k
            i++;
310
1.30k
          }
311
312
1.39k
        if (!(s < s_end))
313
          /* End of string reached.  */
314
372
          break;
315
316
1.02k
        s += count;
317
1.02k
      }
318
372
  }
319
320
372
  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
372
  else if (result != resultbuf && length < allocated)
334
372
    {
335
      /* Shrink the allocated memory if possible.  */
336
372
      UNIT *memory = (UNIT *) realloc (result, length * sizeof (UNIT));
337
372
      if (memory != NULL)
338
372
        result = memory;
339
372
    }
340
341
372
  if (sortbuf_count > 0)
342
0
    abort ();
343
372
  if (sortbuf != sortbuf_preallocated)
344
372
    free (sortbuf);
345
346
372
  *lengthp = length;
347
372
  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
372
}