Coverage Report

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