Coverage Report

Created: 2026-07-10 06:45

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