Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/fontconfig/src/fccharset.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * fontconfig/src/fccharset.c
3
 *
4
 * Copyright © 2001 Keith Packard
5
 *
6
 * Permission to use, copy, modify, distribute, and sell this software and its
7
 * documentation for any purpose is hereby granted without fee, provided that
8
 * the above copyright notice appear in all copies and that both that
9
 * copyright notice and this permission notice appear in supporting
10
 * documentation, and that the name of the author(s) not be used in
11
 * advertising or publicity pertaining to distribution of the software without
12
 * specific, written prior permission.  The authors make no
13
 * representations about the suitability of this software for any purpose.  It
14
 * is provided "as is" without express or implied warranty.
15
 *
16
 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18
 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22
 * PERFORMANCE OF THIS SOFTWARE.
23
 */
24
25
#include "fcint.h"
26
27
#include <stdlib.h>
28
29
/* #define CHECK */
30
31
FcCharSet *
32
FcCharSetCreate (void)
33
26
{
34
26
    FcCharSet *fcs;
35
36
26
    fcs = (FcCharSet *)malloc (sizeof (FcCharSet));
37
26
    if (!fcs)
38
0
  return 0;
39
26
    FcRefInit (&fcs->ref, 1);
40
26
    fcs->num = 0;
41
26
    fcs->leaves_offset = 0;
42
26
    fcs->numbers_offset = 0;
43
26
    return fcs;
44
26
}
45
46
FcCharSet *
47
FcCharSetPromote (FcValuePromotionBuffer *vbuf)
48
0
{
49
0
    FcCharSet *fcs = (FcCharSet *)vbuf;
50
51
0
    FC_ASSERT_STATIC (sizeof (FcCharSet) <= sizeof (FcValuePromotionBuffer));
52
53
0
    FcRefSetConst (&fcs->ref);
54
0
    fcs->num = 0;
55
0
    fcs->leaves_offset = 0;
56
0
    fcs->numbers_offset = 0;
57
58
0
    return fcs;
59
0
}
60
61
FcCharSet *
62
FcCharSetNew (void)
63
0
{
64
0
    return FcCharSetCreate();
65
0
}
66
67
void
68
FcCharSetDestroy (FcCharSet *fcs)
69
4.17k
{
70
4.17k
    int i;
71
72
4.17k
    if (fcs) {
73
4.16k
  if (FcRefIsConst (&fcs->ref)) {
74
4.12k
      FcCacheObjectDereference (fcs);
75
4.12k
      return;
76
4.12k
  }
77
39
  if (FcRefDec (&fcs->ref) != 1)
78
26
      return;
79
288
  for (i = 0; i < fcs->num; i++)
80
275
      free (FcCharSetLeaf (fcs, i));
81
13
  if (fcs->num) {
82
13
      free (FcCharSetLeaves (fcs));
83
13
      free (FcCharSetNumbers (fcs));
84
13
  }
85
13
  free (fcs);
86
13
    }
87
4.17k
}
88
89
/*
90
 * Search for the leaf containing with the specified num.
91
 * Return its index if it exists, otherwise return negative of
92
 * the (position + 1) where it should be inserted
93
 */
94
95
static int
96
FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num)
97
40.0k
{
98
40.0k
    FcChar16 *numbers = FcCharSetNumbers (fcs);
99
40.0k
    FcChar16  page;
100
40.0k
    int       low = start;
101
40.0k
    int       high = fcs->num - 1;
102
103
40.0k
    if (!numbers)
104
0
  return -1;
105
125k
    while (low <= high) {
106
121k
  int mid = (low + high) >> 1;
107
121k
  page = numbers[mid];
108
121k
  if (page == num)
109
36.6k
      return mid;
110
85.2k
  if (page < num)
111
64.5k
      low = mid + 1;
112
20.7k
  else
113
20.7k
      high = mid - 1;
114
85.2k
    }
115
3.38k
    if (high < 0 || (high < fcs->num && numbers[high] < num))
116
3.38k
  high++;
117
3.38k
    return -(high + 1);
118
40.0k
}
119
120
/*
121
 * Locate the leaf containing the specified char, return
122
 * its index if it exists, otherwise return negative of
123
 * the (position + 1) where it should be inserted
124
 */
125
126
static int
127
FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
128
40.0k
{
129
40.0k
    return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
130
40.0k
}
131
132
static FcCharLeaf *
133
FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
134
0
{
135
0
    int pos = FcCharSetFindLeafPos (fcs, ucs4);
136
0
    if (pos >= 0)
137
0
  return FcCharSetLeaf (fcs, pos);
138
0
    return 0;
139
0
}
140
141
550
#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x) - 1)))
142
143
static FcBool
144
FcCharSetPutLeaf (FcCharSet  *fcs,
145
                  FcChar32    ucs4,
146
                  FcCharLeaf *leaf,
147
                  int         pos)
148
550
{
149
550
    intptr_t *leaves = FcCharSetLeaves (fcs);
150
550
    FcChar16 *numbers = FcCharSetNumbers (fcs);
151
152
550
    ucs4 >>= 8;
153
550
    if (ucs4 >= 0x10000)
154
0
  return FcFalse;
155
156
550
    if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num)) {
157
156
  if (!fcs->num) {
158
26
      unsigned int alloced = 8;
159
26
      leaves = malloc (alloced * sizeof (*leaves));
160
26
      numbers = malloc (alloced * sizeof (*numbers));
161
26
      if (!leaves || !numbers) {
162
0
    if (leaves)
163
0
        free (leaves);
164
0
    if (numbers)
165
0
        free (numbers);
166
0
    return FcFalse;
167
0
      }
168
130
  } else {
169
130
      int          i;
170
130
      unsigned int alloced = fcs->num;
171
130
      intptr_t    *new_leaves;
172
173
130
      alloced *= 2;
174
130
      numbers = realloc (numbers, alloced * sizeof (*numbers));
175
130
      if (!numbers)
176
0
    return FcFalse;
177
130
      new_leaves = realloc (leaves, alloced * sizeof (*leaves));
178
130
      if (!new_leaves) {
179
    /*
180
     * Revert the reallocation of numbers. We update numbers_offset
181
     * first in case realloc() fails.
182
     */
183
0
    fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
184
0
    numbers = realloc (numbers, (alloced / 2) * sizeof (*numbers));
185
    /* unlikely to fail though */
186
0
    if (!numbers)
187
0
        return FcFalse;
188
0
    fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
189
0
    return FcFalse;
190
0
      }
191
936
      for (i = 0; i < fcs->num; i++) {
192
    // Reconstruct FcCharLeaf* from offset, similar to how FcCharSetLeaf() macro operates
193
806
    FcCharLeaf *leaf = FcOffsetToPtr (leaves, new_leaves[i], FcCharLeaf);
194
806
    new_leaves[i] = FcPtrToOffset (new_leaves, leaf);
195
806
      }
196
130
      leaves = new_leaves;
197
130
  }
198
199
156
  fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
200
156
  fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
201
156
    }
202
203
550
    memmove (leaves + pos + 1, leaves + pos,
204
550
             (fcs->num - pos) * sizeof (*leaves));
205
550
    memmove (numbers + pos + 1, numbers + pos,
206
550
             (fcs->num - pos) * sizeof (*numbers));
207
550
    numbers[pos] = (FcChar16)ucs4;
208
550
    leaves[pos] = FcPtrToOffset (leaves, leaf);
209
550
    fcs->num++;
210
550
    return FcTrue;
211
550
}
212
213
/*
214
 * Locate the leaf containing the specified char, creating it
215
 * if desired
216
 */
217
218
FcCharLeaf *
219
FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
220
28.8k
{
221
28.8k
    int         pos;
222
28.8k
    FcCharLeaf *leaf;
223
224
28.8k
    pos = FcCharSetFindLeafPos (fcs, ucs4);
225
28.8k
    if (pos >= 0)
226
28.6k
  return FcCharSetLeaf (fcs, pos);
227
228
275
    leaf = calloc (1, sizeof (FcCharLeaf));
229
275
    if (!leaf)
230
0
  return 0;
231
232
275
    pos = -pos - 1;
233
275
    if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos)) {
234
0
  free (leaf);
235
0
  return 0;
236
0
    }
237
275
    return leaf;
238
275
}
239
240
static FcBool
241
FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
242
275
{
243
275
    int pos;
244
245
275
    pos = FcCharSetFindLeafPos (fcs, ucs4);
246
275
    if (pos >= 0) {
247
0
  free (FcCharSetLeaf (fcs, pos));
248
0
  FcCharSetLeaves (fcs)[pos] = FcPtrToOffset (FcCharSetLeaves (fcs),
249
0
                                              leaf);
250
0
  return FcTrue;
251
0
    }
252
275
    pos = -pos - 1;
253
275
    return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
254
275
}
255
256
FcBool
257
FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
258
28.8k
{
259
28.8k
    FcCharLeaf *leaf;
260
28.8k
    FcChar32   *b;
261
262
28.8k
    if (fcs == NULL || FcRefIsConst (&fcs->ref))
263
0
  return FcFalse;
264
28.8k
    leaf = FcCharSetFindLeafCreate (fcs, ucs4);
265
28.8k
    if (!leaf)
266
0
  return FcFalse;
267
28.8k
    b = &leaf->map[(ucs4 & 0xff) >> 5];
268
28.8k
    *b |= (1U << (ucs4 & 0x1f));
269
28.8k
    return FcTrue;
270
28.8k
}
271
272
FcBool
273
FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4)
274
0
{
275
0
    FcCharLeaf *leaf;
276
0
    FcChar32   *b;
277
278
0
    if (fcs == NULL || FcRefIsConst (&fcs->ref))
279
0
  return FcFalse;
280
0
    leaf = FcCharSetFindLeaf (fcs, ucs4);
281
0
    if (!leaf)
282
0
  return FcTrue;
283
0
    b = &leaf->map[(ucs4 & 0xff) >> 5];
284
0
    *b &= ~(1U << (ucs4 & 0x1f));
285
    /* We don't bother removing the leaf if it's empty */
286
0
    return FcTrue;
287
0
}
288
289
/*
290
 * An iterator for the leaves of a charset
291
 */
292
293
typedef struct _fcCharSetIter {
294
    FcCharLeaf *leaf;
295
    FcChar32    ucs4;
296
    int         pos;
297
} FcCharSetIter;
298
299
/*
300
 * Set iter->leaf to the leaf containing iter->ucs4 or higher
301
 */
302
303
static void
304
FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
305
10.8k
{
306
10.8k
    int pos = FcCharSetFindLeafPos (fcs, iter->ucs4);
307
308
10.8k
    if (pos < 0) {
309
2.83k
  pos = -pos - 1;
310
2.83k
  if (pos == fcs->num) {
311
83
      iter->ucs4 = ~0;
312
83
      iter->leaf = 0;
313
83
      return;
314
83
  }
315
2.75k
  iter->ucs4 = (FcChar32)FcCharSetNumbers (fcs)[pos] << 8;
316
2.75k
    }
317
10.8k
    iter->leaf = FcCharSetLeaf (fcs, pos);
318
10.8k
    iter->pos = pos;
319
10.8k
}
320
321
static void
322
FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
323
21.8k
{
324
21.8k
    int pos = iter->pos + 1;
325
21.8k
    if (pos >= fcs->num) {
326
3.66k
  iter->ucs4 = ~0;
327
3.66k
  iter->leaf = 0;
328
18.1k
    } else {
329
18.1k
  iter->ucs4 = (FcChar32)FcCharSetNumbers (fcs)[pos] << 8;
330
18.1k
  iter->leaf = FcCharSetLeaf (fcs, pos);
331
18.1k
  iter->pos = pos;
332
18.1k
    }
333
21.8k
}
334
335
static void
336
FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
337
7.31k
{
338
7.31k
    iter->ucs4 = 0;
339
7.31k
    iter->pos = 0;
340
7.31k
    FcCharSetIterSet (fcs, iter);
341
7.31k
}
342
343
FcCharSet *
344
FcCharSetCopy (FcCharSet *src)
345
4.18k
{
346
4.18k
    if (src) {
347
4.18k
  if (!FcRefIsConst (&src->ref))
348
26
      FcRefInc (&src->ref);
349
4.15k
  else
350
4.15k
      FcCacheObjectReference (src);
351
4.18k
    }
352
4.18k
    return src;
353
4.18k
}
354
355
FcBool
356
FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
357
0
{
358
0
    FcCharSetIter ai, bi;
359
0
    int           i;
360
361
0
    if (a == b)
362
0
  return FcTrue;
363
0
    if (!a || !b)
364
0
  return FcFalse;
365
0
    for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi);
366
0
         ai.leaf && bi.leaf;
367
0
         FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi)) {
368
0
  if (ai.ucs4 != bi.ucs4)
369
0
      return FcFalse;
370
0
  for (i = 0; i < 256 / 32; i++)
371
0
      if (ai.leaf->map[i] != bi.leaf->map[i])
372
0
    return FcFalse;
373
0
    }
374
0
    return ai.leaf == bi.leaf;
375
0
}
376
377
static FcBool
378
FcCharSetAddLeaf (FcCharSet  *fcs,
379
                  FcChar32    ucs4,
380
                  FcCharLeaf *leaf)
381
0
{
382
0
    FcCharLeaf *newp = FcCharSetFindLeafCreate (fcs, ucs4);
383
0
    if (!newp)
384
0
  return FcFalse;
385
0
    *newp = *leaf;
386
0
    return FcTrue;
387
0
}
388
389
static FcCharSet *
390
FcCharSetOperate (const FcCharSet *a,
391
                  const FcCharSet *b,
392
                  FcBool (*overlap) (FcCharLeaf       *result,
393
                                     const FcCharLeaf *al,
394
                                     const FcCharLeaf *bl),
395
                  FcBool aonly,
396
                  FcBool bonly)
397
0
{
398
0
    FcCharSet    *fcs;
399
0
    FcCharSetIter ai, bi;
400
401
0
    if (!a || !b)
402
0
  goto bail0;
403
0
    fcs = FcCharSetCreate();
404
0
    if (!fcs)
405
0
  goto bail0;
406
0
    FcCharSetIterStart (a, &ai);
407
0
    FcCharSetIterStart (b, &bi);
408
0
    while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf))) {
409
0
  if (ai.ucs4 < bi.ucs4) {
410
0
      if (aonly) {
411
0
    if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
412
0
        goto bail1;
413
0
    FcCharSetIterNext (a, &ai);
414
0
      } else {
415
0
    ai.ucs4 = bi.ucs4;
416
0
    FcCharSetIterSet (a, &ai);
417
0
      }
418
0
  } else if (bi.ucs4 < ai.ucs4) {
419
0
      if (bonly) {
420
0
    if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
421
0
        goto bail1;
422
0
    FcCharSetIterNext (b, &bi);
423
0
      } else {
424
0
    bi.ucs4 = ai.ucs4;
425
0
    FcCharSetIterSet (b, &bi);
426
0
      }
427
0
  } else {
428
0
      FcCharLeaf leaf;
429
430
0
      if ((*overlap) (&leaf, ai.leaf, bi.leaf)) {
431
0
    if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
432
0
        goto bail1;
433
0
      }
434
0
      FcCharSetIterNext (a, &ai);
435
0
      FcCharSetIterNext (b, &bi);
436
0
  }
437
0
    }
438
0
    return fcs;
439
0
bail1:
440
0
    FcCharSetDestroy (fcs);
441
0
bail0:
442
0
    return 0;
443
0
}
444
445
static FcBool
446
FcCharSetIntersectLeaf (FcCharLeaf       *result,
447
                        const FcCharLeaf *al,
448
                        const FcCharLeaf *bl)
449
0
{
450
0
    int    i;
451
0
    FcBool nonempty = FcFalse;
452
453
0
    for (i = 0; i < 256 / 32; i++)
454
0
  if ((result->map[i] = al->map[i] & bl->map[i]))
455
0
      nonempty = FcTrue;
456
0
    return nonempty;
457
0
}
458
459
FcCharSet *
460
FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
461
0
{
462
0
    return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse);
463
0
}
464
465
static FcBool
466
FcCharSetUnionLeaf (FcCharLeaf       *result,
467
                    const FcCharLeaf *al,
468
                    const FcCharLeaf *bl)
469
0
{
470
0
    int i;
471
472
0
    for (i = 0; i < 256 / 32; i++)
473
0
  result->map[i] = al->map[i] | bl->map[i];
474
0
    return FcTrue;
475
0
}
476
477
FcCharSet *
478
FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
479
0
{
480
0
    return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
481
0
}
482
483
FcBool
484
FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
485
0
{
486
0
    int      ai = 0, bi = 0;
487
0
    FcChar16 an, bn;
488
489
0
    if (!a || !b)
490
0
  return FcFalse;
491
492
0
    if (FcRefIsConst (&a->ref)) {
493
0
  if (changed)
494
0
      *changed = FcFalse;
495
0
  return FcFalse;
496
0
    }
497
498
0
    if (changed) {
499
0
  *changed = !FcCharSetIsSubset (b, a);
500
0
  if (!*changed)
501
0
      return FcTrue;
502
0
    }
503
504
0
    while (bi < b->num) {
505
0
  an = ai < a->num ? FcCharSetNumbers (a)[ai] : ~0;
506
0
  bn = FcCharSetNumbers (b)[bi];
507
508
0
  if (an < bn) {
509
0
      ai = FcCharSetFindLeafForward (a, ai + 1, bn);
510
0
      if (ai < 0)
511
0
    ai = -ai - 1;
512
0
  } else {
513
0
      FcCharLeaf *bl = FcCharSetLeaf (b, bi);
514
0
      if (bn < an) {
515
0
    if (!FcCharSetAddLeaf (a, bn << 8, bl))
516
0
        return FcFalse;
517
0
      } else {
518
0
    FcCharLeaf *al = FcCharSetLeaf (a, ai);
519
0
    FcCharSetUnionLeaf (al, al, bl);
520
0
      }
521
522
0
      ai++;
523
0
      bi++;
524
0
  }
525
0
    }
526
527
0
    return FcTrue;
528
0
}
529
530
static FcBool
531
FcCharSetSubtractLeaf (FcCharLeaf       *result,
532
                       const FcCharLeaf *al,
533
                       const FcCharLeaf *bl)
534
0
{
535
0
    int    i;
536
0
    FcBool nonempty = FcFalse;
537
538
0
    for (i = 0; i < 256 / 32; i++)
539
0
  if ((result->map[i] = al->map[i] & ~bl->map[i]))
540
0
      nonempty = FcTrue;
541
0
    return nonempty;
542
0
}
543
544
FcCharSet *
545
FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
546
0
{
547
0
    return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
548
0
}
549
550
FcBool
551
FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
552
0
{
553
0
    FcCharLeaf *leaf;
554
555
0
    if (!fcs)
556
0
  return FcFalse;
557
0
    leaf = FcCharSetFindLeaf (fcs, ucs4);
558
0
    if (!leaf)
559
0
  return FcFalse;
560
0
    return (leaf->map[(ucs4 & 0xff) >> 5] & (1U << (ucs4 & 0x1f))) != 0;
561
0
}
562
563
static FcChar32
564
FcCharSetPopCount (FcChar32 c1)
565
174k
{
566
174k
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
567
174k
    return __builtin_popcount (c1);
568
#else
569
    /* hackmem 169 */
570
    FcChar32 c2 = (c1 >> 1) & 033333333333;
571
    c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
572
    return (((c2 + (c2 >> 3)) & 030707070707) % 077);
573
#endif
574
174k
}
575
576
FcChar32
577
FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
578
0
{
579
0
    FcCharSetIter ai, bi;
580
0
    FcChar32      count = 0;
581
582
0
    if (a && b) {
583
0
  FcCharSetIterStart (a, &ai);
584
0
  FcCharSetIterStart (b, &bi);
585
0
  while (ai.leaf && bi.leaf) {
586
0
      if (ai.ucs4 == bi.ucs4) {
587
0
    FcChar32 *am = ai.leaf->map;
588
0
    FcChar32 *bm = bi.leaf->map;
589
0
    int       i = 256 / 32;
590
0
    while (i--)
591
0
        count += FcCharSetPopCount (*am++ & *bm++);
592
0
    FcCharSetIterNext (a, &ai);
593
0
      } else if (ai.ucs4 < bi.ucs4) {
594
0
    ai.ucs4 = bi.ucs4;
595
0
    FcCharSetIterSet (a, &ai);
596
0
      }
597
0
      if (bi.ucs4 < ai.ucs4) {
598
0
    bi.ucs4 = ai.ucs4;
599
0
    FcCharSetIterSet (b, &bi);
600
0
      }
601
0
  }
602
0
    }
603
0
    return count;
604
0
}
605
606
FcChar32
607
FcCharSetCount (const FcCharSet *a)
608
13
{
609
13
    FcCharSetIter ai;
610
13
    FcChar32      count = 0;
611
612
13
    if (a) {
613
288
  for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai)) {
614
275
      int       i = 256 / 32;
615
275
      FcChar32 *am = ai.leaf->map;
616
617
2.47k
      while (i--)
618
2.20k
    count += FcCharSetPopCount (*am++);
619
275
  }
620
13
    }
621
13
    return count;
622
13
}
623
624
FcChar32
625
FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
626
3.65k
{
627
3.65k
    FcCharSetIter ai, bi;
628
3.65k
    FcChar32      count = 0;
629
630
3.65k
    if (a && b) {
631
3.65k
  FcCharSetIterStart (a, &ai);
632
3.65k
  FcCharSetIterStart (b, &bi);
633
28.7k
  while (ai.leaf) {
634
25.1k
      if (ai.ucs4 <= bi.ucs4) {
635
21.5k
    FcChar32 *am = ai.leaf->map;
636
21.5k
    int       i = 256 / 32;
637
21.5k
    if (ai.ucs4 == bi.ucs4) {
638
4.39k
        FcChar32 *bm = bi.leaf->map;
639
39.5k
        while (i--)
640
35.1k
      count += FcCharSetPopCount (*am++ & ~*bm++);
641
17.1k
    } else {
642
154k
        while (i--)
643
137k
      count += FcCharSetPopCount (*am++);
644
17.1k
    }
645
21.5k
    FcCharSetIterNext (a, &ai);
646
21.5k
      } else if (bi.leaf) {
647
3.57k
    bi.ucs4 = ai.ucs4;
648
3.57k
    FcCharSetIterSet (b, &bi);
649
3.57k
      }
650
25.1k
  }
651
3.65k
    }
652
3.65k
    return count;
653
3.65k
}
654
655
/*
656
 * return FcTrue iff a is a subset of b
657
 */
658
FcBool
659
FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
660
0
{
661
0
    int      ai, bi;
662
0
    FcChar16 an, bn;
663
664
0
    if (a == b)
665
0
  return FcTrue;
666
0
    if (!a || !b)
667
0
  return FcFalse;
668
0
    bi = 0;
669
0
    ai = 0;
670
0
    while (ai < a->num && bi < b->num) {
671
0
  an = FcCharSetNumbers (a)[ai];
672
0
  bn = FcCharSetNumbers (b)[bi];
673
  /*
674
   * Check matching pages
675
   */
676
0
  if (an == bn) {
677
0
      FcChar32 *am = FcCharSetLeaf (a, ai)->map;
678
0
      FcChar32 *bm = FcCharSetLeaf (b, bi)->map;
679
680
0
      if (am != bm) {
681
0
    int i = 256 / 32;
682
    /*
683
     * Does am have any bits not in bm?
684
     */
685
0
    while (i--)
686
0
        if (*am++ & ~*bm++)
687
0
      return FcFalse;
688
0
      }
689
0
      ai++;
690
0
      bi++;
691
0
  }
692
  /*
693
   * Does a have any pages not in b?
694
   */
695
0
  else if (an < bn)
696
0
      return FcFalse;
697
0
  else {
698
0
      bi = FcCharSetFindLeafForward (b, bi + 1, an);
699
0
      if (bi < 0)
700
0
    bi = -bi - 1;
701
0
  }
702
0
    }
703
    /*
704
     * did we look at every page?
705
     */
706
0
    return ai >= a->num;
707
0
}
708
709
/*
710
 * These two functions efficiently walk the entire charmap for
711
 * other software (like pango) that want their own copy
712
 */
713
714
FcChar32
715
FcCharSetNextPage (const FcCharSet *a,
716
                   FcChar32         map[FC_CHARSET_MAP_SIZE],
717
                   FcChar32        *next)
718
0
{
719
0
    FcCharSetIter ai;
720
0
    FcChar32      page;
721
722
0
    if (!a)
723
0
  return FC_CHARSET_DONE;
724
0
    ai.ucs4 = *next;
725
0
    FcCharSetIterSet (a, &ai);
726
0
    if (!ai.leaf)
727
0
  return FC_CHARSET_DONE;
728
729
    /*
730
     * Save current information
731
     */
732
0
    page = ai.ucs4;
733
0
    memcpy (map, ai.leaf->map, sizeof (ai.leaf->map));
734
    /*
735
     * Step to next page
736
     */
737
0
    FcCharSetIterNext (a, &ai);
738
0
    *next = ai.ucs4;
739
740
0
    return page;
741
0
}
742
743
FcChar32
744
FcCharSetFirstPage (const FcCharSet *a,
745
                    FcChar32         map[FC_CHARSET_MAP_SIZE],
746
                    FcChar32        *next)
747
0
{
748
0
    *next = 0;
749
0
    return FcCharSetNextPage (a, map, next);
750
0
}
751
752
/*
753
 * old coverage API, rather hard to use correctly
754
 */
755
756
FcChar32
757
FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result)
758
0
{
759
0
    FcCharSetIter ai;
760
761
0
    ai.ucs4 = page;
762
0
    FcCharSetIterSet (a, &ai);
763
0
    if (!ai.leaf) {
764
0
  memset (result, '\0', 256 / 8);
765
0
  page = 0;
766
0
    } else {
767
0
  memcpy (result, ai.leaf->map, sizeof (ai.leaf->map));
768
0
  FcCharSetIterNext (a, &ai);
769
0
  page = ai.ucs4;
770
0
    }
771
0
    return page;
772
0
}
773
774
static FcBool
775
FcNameParseRange (FcChar8 **string, FcChar32 *pfirst, FcChar32 *plast)
776
0
{
777
0
    char *s = (char *)*string;
778
0
    char *t;
779
0
    long  first, last;
780
781
0
    while (isspace ((unsigned char)*s))
782
0
  s++;
783
0
    t = s;
784
0
    errno = 0;
785
0
    first = last = strtol (s, &s, 16);
786
0
    if (errno)
787
0
  return FcFalse;
788
0
    while (isspace ((unsigned char)*s))
789
0
  s++;
790
0
    if (*s == '-') {
791
0
  s++;
792
0
  errno = 0;
793
0
  last = strtol (s, &s, 16);
794
0
  if (errno)
795
0
      return FcFalse;
796
0
    }
797
798
0
    if (s == t || first < 0 || last < 0 || last < first || last > 0x10ffff)
799
0
  return FcFalse;
800
801
0
    *string = (FcChar8 *)s;
802
0
    *pfirst = first;
803
0
    *plast = last;
804
0
    return FcTrue;
805
0
}
806
807
FcCharSet *
808
FcNameParseCharSet (FcChar8 *string)
809
0
{
810
0
    FcCharSet *c;
811
0
    FcChar32   first, last;
812
813
0
    c = FcCharSetCreate();
814
0
    if (!c)
815
0
  goto bail0;
816
0
    while (*string) {
817
0
  FcChar32 u;
818
819
0
  if (!FcNameParseRange (&string, &first, &last))
820
0
      goto bail1;
821
822
0
  for (u = first; u < last + 1; u++)
823
0
      FcCharSetAddChar (c, u);
824
0
    }
825
0
    return c;
826
0
bail1:
827
0
    FcCharSetDestroy (c);
828
0
bail0:
829
0
    return NULL;
830
0
}
831
832
static void
833
FcNameUnparseUnicode (FcStrBuf *buf, FcChar32 u)
834
0
{
835
0
    FcChar8 buf_static[64];
836
0
    snprintf ((char *)buf_static, sizeof (buf_static), "%x", u);
837
0
    FcStrBufString (buf, buf_static);
838
0
}
839
840
FcBool
841
FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
842
0
{
843
0
    FcCharSetIter ci;
844
0
    FcChar32      first, last;
845
0
    int           i;
846
#ifdef CHECK
847
    int len = buf->len;
848
#endif
849
850
0
    first = last = 0x7FFFFFFF;
851
852
0
    for (FcCharSetIterStart (c, &ci);
853
0
         ci.leaf;
854
0
         FcCharSetIterNext (c, &ci)) {
855
0
  for (i = 0; i < 256 / 32; i++) {
856
0
      FcChar32 bits = ci.leaf->map[i];
857
0
      FcChar32 u = ci.ucs4 + i * 32;
858
859
0
      while (bits) {
860
0
    if (bits & 1) {
861
0
        if (u != last + 1) {
862
0
      if (last != first) {
863
0
          FcStrBufChar (buf, '-');
864
0
          FcNameUnparseUnicode (buf, last);
865
0
      }
866
0
      if (last != 0x7FFFFFFF)
867
0
          FcStrBufChar (buf, ' ');
868
      /* Start new range. */
869
0
      first = u;
870
0
      FcNameUnparseUnicode (buf, u);
871
0
        }
872
0
        last = u;
873
0
    }
874
0
    bits >>= 1;
875
0
    u++;
876
0
      }
877
0
  }
878
0
    }
879
0
    if (last != first) {
880
0
  FcStrBufChar (buf, '-');
881
0
  FcNameUnparseUnicode (buf, last);
882
0
    }
883
#ifdef CHECK
884
    {
885
  FcCharSet    *check;
886
  FcChar32      missing;
887
  FcCharSetIter ci, checki;
888
889
  /* null terminate for parser */
890
  FcStrBufChar (buf, '\0');
891
  /* step back over null for life after test */
892
  buf->len--;
893
  check = FcNameParseCharSet (buf->buf + len);
894
  FcCharSetIterStart (c, &ci);
895
  FcCharSetIterStart (check, &checki);
896
  while (ci.leaf || checki.leaf) {
897
      if (ci.ucs4 < checki.ucs4) {
898
    printf ("Missing leaf node at 0x%x\n", ci.ucs4);
899
    FcCharSetIterNext (c, &ci);
900
      } else if (checki.ucs4 < ci.ucs4) {
901
    printf ("Extra leaf node at 0x%x\n", checki.ucs4);
902
    FcCharSetIterNext (check, &checki);
903
      } else {
904
    int       i = 256 / 32;
905
    FcChar32 *cm = ci.leaf->map;
906
    FcChar32 *checkm = checki.leaf->map;
907
908
    for (i = 0; i < 256; i += 32) {
909
        if (*cm != *checkm)
910
      printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
911
              ci.ucs4 + i, *cm, *checkm);
912
        cm++;
913
        checkm++;
914
    }
915
    FcCharSetIterNext (c, &ci);
916
    FcCharSetIterNext (check, &checki);
917
      }
918
  }
919
  if ((missing = FcCharSetSubtractCount (c, check)))
920
      printf ("%d missing in reparsed result\n", missing);
921
  if ((missing = FcCharSetSubtractCount (check, c)))
922
      printf ("%d extra in reparsed result\n", missing);
923
  FcCharSetDestroy (check);
924
    }
925
#endif
926
927
0
    return FcTrue;
928
0
}
929
930
typedef struct _FcCharLeafEnt FcCharLeafEnt;
931
932
struct _FcCharLeafEnt {
933
    FcCharLeafEnt *next;
934
    FcChar32       hash;
935
    FcCharLeaf     leaf;
936
};
937
938
2
#define FC_CHAR_LEAF_BLOCK     (4096 / sizeof (FcCharLeafEnt))
939
275
#define FC_CHAR_LEAF_HASH_SIZE 257
940
941
typedef struct _FcCharSetEnt FcCharSetEnt;
942
943
struct _FcCharSetEnt {
944
    FcCharSetEnt *next;
945
    FcChar32      hash;
946
    FcCharSet     set;
947
};
948
949
typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
950
951
struct _FcCharSetOrigEnt {
952
    FcCharSetOrigEnt *next;
953
    const FcCharSet  *orig;
954
    const FcCharSet  *frozen;
955
};
956
957
188
#define FC_CHAR_SET_HASH_SIZE 67
958
959
struct _FcCharSetFreezer {
960
    FcCharLeafEnt    *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE];
961
    FcCharLeafEnt   **leaf_blocks;
962
    int               leaf_block_count;
963
    FcCharSetEnt     *set_hash_table[FC_CHAR_SET_HASH_SIZE];
964
    FcCharSetOrigEnt *orig_hash_table[FC_CHAR_SET_HASH_SIZE];
965
    FcCharLeafEnt    *current_block;
966
    int               leaf_remain;
967
    int               leaves_seen;
968
    int               charsets_seen;
969
    int               leaves_allocated;
970
    int               charsets_allocated;
971
};
972
973
static FcCharLeafEnt *
974
FcCharLeafEntCreate (FcCharSetFreezer *freezer)
975
48
{
976
48
    if (!freezer->leaf_remain) {
977
1
  FcCharLeafEnt **newBlocks;
978
979
1
  freezer->leaf_block_count++;
980
1
  newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
981
1
  if (!newBlocks)
982
0
      return 0;
983
1
  freezer->leaf_blocks = newBlocks;
984
1
  freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count - 1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
985
1
  if (!freezer->current_block)
986
0
      return 0;
987
1
  freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
988
1
    }
989
48
    freezer->leaf_remain--;
990
48
    freezer->leaves_allocated++;
991
48
    return freezer->current_block++;
992
48
}
993
994
static FcChar32
995
FcCharLeafHash (FcCharLeaf *leaf)
996
550
{
997
550
    FcChar32 hash = 0;
998
550
    int      i;
999
1000
4.95k
    for (i = 0; i < 256 / 32; i++)
1001
4.40k
  hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
1002
550
    return hash;
1003
550
}
1004
1005
static FcCharLeaf *
1006
FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
1007
275
{
1008
275
    FcChar32        hash = FcCharLeafHash (leaf);
1009
275
    FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
1010
275
    FcCharLeafEnt  *ent;
1011
1012
308
    for (ent = *bucket; ent; ent = ent->next) {
1013
260
  if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
1014
227
      return &ent->leaf;
1015
260
    }
1016
1017
48
    ent = FcCharLeafEntCreate (freezer);
1018
48
    if (!ent)
1019
0
  return 0;
1020
48
    ent->leaf = *leaf;
1021
48
    ent->hash = hash;
1022
48
    ent->next = *bucket;
1023
48
    *bucket = ent;
1024
48
    return &ent->leaf;
1025
48
}
1026
1027
static FcChar32
1028
FcCharSetHash (FcCharSet *fcs)
1029
13
{
1030
13
    FcChar32 hash = 0;
1031
13
    int      i;
1032
1033
    /* hash in leaves */
1034
288
    for (i = 0; i < fcs->num; i++)
1035
275
  hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf (fcs, i));
1036
    /* hash in numbers */
1037
288
    for (i = 0; i < fcs->num; i++)
1038
275
  hash = ((hash << 1) | (hash >> 31)) ^ FcCharSetNumbers (fcs)[i];
1039
13
    return hash;
1040
13
}
1041
1042
static FcBool
1043
FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
1044
13
{
1045
13
    FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t)orig) % FC_CHAR_SET_HASH_SIZE];
1046
13
    FcCharSetOrigEnt  *ent;
1047
1048
13
    ent = malloc (sizeof (FcCharSetOrigEnt));
1049
13
    if (!ent)
1050
0
  return FcFalse;
1051
13
    ent->orig = orig;
1052
13
    ent->frozen = frozen;
1053
13
    ent->next = *bucket;
1054
13
    *bucket = ent;
1055
13
    return FcTrue;
1056
13
}
1057
1058
static FcCharSet *
1059
FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs)
1060
13
{
1061
13
    FcChar32       hash = FcCharSetHash (fcs);
1062
13
    FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
1063
13
    FcCharSetEnt  *ent;
1064
13
    int            size;
1065
13
    int            i;
1066
1067
14
    for (ent = *bucket; ent; ent = ent->next) {
1068
8
  if (ent->hash == hash &&
1069
8
      ent->set.num == fcs->num &&
1070
8
      !memcmp (FcCharSetNumbers (&ent->set),
1071
7
               FcCharSetNumbers (fcs),
1072
7
               fcs->num * sizeof (FcChar16))) {
1073
7
      FcBool ok = FcTrue;
1074
7
      int    i;
1075
1076
152
      for (i = 0; i < fcs->num; i++)
1077
145
    if (FcCharSetLeaf (&ent->set, i) != FcCharSetLeaf (fcs, i))
1078
0
        ok = FcFalse;
1079
7
      if (ok)
1080
7
    return &ent->set;
1081
7
  }
1082
8
    }
1083
1084
6
    size = (sizeof (FcCharSetEnt) +
1085
6
            fcs->num * sizeof (FcCharLeaf *) +
1086
6
            fcs->num * sizeof (FcChar16));
1087
6
    ent = malloc (size);
1088
6
    if (!ent)
1089
0
  return 0;
1090
1091
6
    freezer->charsets_allocated++;
1092
1093
6
    FcRefSetConst (&ent->set.ref);
1094
6
    ent->set.num = fcs->num;
1095
6
    if (fcs->num) {
1096
6
  intptr_t *ent_leaves;
1097
1098
6
  ent->set.leaves_offset = sizeof (ent->set);
1099
6
  ent->set.numbers_offset = (ent->set.leaves_offset +
1100
6
                             fcs->num * sizeof (intptr_t));
1101
1102
6
  ent_leaves = FcCharSetLeaves (&ent->set);
1103
136
  for (i = 0; i < fcs->num; i++)
1104
130
      ent_leaves[i] = FcPtrToOffset (ent_leaves,
1105
6
                                     FcCharSetLeaf (fcs, i));
1106
6
  memcpy (FcCharSetNumbers (&ent->set),
1107
6
          FcCharSetNumbers (fcs),
1108
6
          fcs->num * sizeof (FcChar16));
1109
6
    } else {
1110
0
  ent->set.leaves_offset = 0;
1111
0
  ent->set.numbers_offset = 0;
1112
0
    }
1113
1114
6
    ent->hash = hash;
1115
6
    ent->next = *bucket;
1116
6
    *bucket = ent;
1117
1118
6
    return &ent->set;
1119
6
}
1120
1121
static const FcCharSet *
1122
FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
1123
26
{
1124
26
    FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t)orig) % FC_CHAR_SET_HASH_SIZE];
1125
26
    FcCharSetOrigEnt  *ent;
1126
1127
28
    for (ent = *bucket; ent; ent = ent->next)
1128
15
  if (ent->orig == orig)
1129
13
      return ent->frozen;
1130
13
    return NULL;
1131
26
}
1132
1133
const FcCharSet *
1134
FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
1135
13
{
1136
13
    FcCharSet       *b;
1137
13
    const FcCharSet *n = 0;
1138
13
    FcCharLeaf      *l;
1139
13
    int              i;
1140
1141
13
    b = FcCharSetCreate();
1142
13
    if (!b)
1143
0
  goto bail0;
1144
288
    for (i = 0; i < fcs->num; i++) {
1145
275
  l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf (fcs, i));
1146
275
  if (!l)
1147
0
      goto bail1;
1148
275
  if (!FcCharSetInsertLeaf (b, FcCharSetNumbers (fcs)[i] << 8, l))
1149
0
      goto bail1;
1150
275
    }
1151
13
    n = FcCharSetFreezeBase (freezer, b);
1152
13
    if (!FcCharSetFreezeOrig (freezer, fcs, n)) {
1153
0
  n = NULL;
1154
0
  goto bail1;
1155
0
    }
1156
13
    freezer->charsets_seen++;
1157
13
    freezer->leaves_seen += fcs->num;
1158
13
bail1:
1159
13
    if (b->num)
1160
13
  free (FcCharSetLeaves (b));
1161
13
    if (b->num)
1162
13
  free (FcCharSetNumbers (b));
1163
13
    free (b);
1164
13
bail0:
1165
13
    return n;
1166
13
}
1167
1168
FcCharSetFreezer *
1169
FcCharSetFreezerCreate (void)
1170
1
{
1171
1
    FcCharSetFreezer *freezer;
1172
1173
1
    freezer = calloc (1, sizeof (FcCharSetFreezer));
1174
1
    return freezer;
1175
1
}
1176
1177
void
1178
FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
1179
1
{
1180
1
    int i;
1181
1182
1
    if (FcDebug() & FC_DBG_CACHE) {
1183
0
  printf ("\ncharsets %d -> %d leaves %d -> %d\n",
1184
0
          freezer->charsets_seen, freezer->charsets_allocated,
1185
0
          freezer->leaves_seen, freezer->leaves_allocated);
1186
0
    }
1187
68
    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) {
1188
67
  FcCharSetEnt *ent, *next;
1189
73
  for (ent = freezer->set_hash_table[i]; ent; ent = next) {
1190
6
      next = ent->next;
1191
6
      free (ent);
1192
6
  }
1193
67
    }
1194
1195
68
    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) {
1196
67
  FcCharSetOrigEnt *ent, *next;
1197
80
  for (ent = freezer->orig_hash_table[i]; ent; ent = next) {
1198
13
      next = ent->next;
1199
13
      free (ent);
1200
13
  }
1201
67
    }
1202
1203
2
    for (i = 0; i < freezer->leaf_block_count; i++)
1204
1
  free (freezer->leaf_blocks[i]);
1205
1206
1
    free (freezer->leaf_blocks);
1207
1
    free (freezer);
1208
1
}
1209
1210
FcBool
1211
FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
1212
13
{
1213
13
    intptr_t *leaves;
1214
13
    FcChar16 *numbers;
1215
13
    int       i;
1216
1217
13
    if (!FcRefIsConst (&cs->ref)) {
1218
13
  if (!serialize->cs_freezer) {
1219
1
      serialize->cs_freezer = FcCharSetFreezerCreate();
1220
1
      if (!serialize->cs_freezer)
1221
0
    return FcFalse;
1222
1
  }
1223
13
  if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
1224
0
      return FcTrue;
1225
1226
13
  cs = FcCharSetFreeze (serialize->cs_freezer, cs);
1227
13
    }
1228
1229
13
    leaves = FcCharSetLeaves (cs);
1230
13
    numbers = FcCharSetNumbers (cs);
1231
1232
13
    if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
1233
0
  return FcFalse;
1234
13
    if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
1235
0
  return FcFalse;
1236
13
    if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
1237
0
  return FcFalse;
1238
288
    for (i = 0; i < cs->num; i++)
1239
275
  if (!FcSerializeAlloc (serialize, FcCharSetLeaf (cs, i),
1240
275
                         sizeof (FcCharLeaf)))
1241
0
      return FcFalse;
1242
13
    return FcTrue;
1243
13
}
1244
1245
FcCharSet *
1246
FcCharSetSerialize (FcSerialize *serialize, const FcCharSet *cs)
1247
13
{
1248
13
    FcCharSet  *cs_serialized;
1249
13
    intptr_t   *leaves, *leaves_serialized;
1250
13
    FcChar16   *numbers, *numbers_serialized;
1251
13
    FcCharLeaf *leaf, *leaf_serialized;
1252
13
    int         i;
1253
1254
13
    if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer) {
1255
13
  cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
1256
13
  if (!cs)
1257
0
      return NULL;
1258
13
    }
1259
1260
13
    cs_serialized = FcSerializePtr (serialize, cs);
1261
13
    if (!cs_serialized)
1262
0
  return NULL;
1263
1264
13
    FcRefSetConst (&cs_serialized->ref);
1265
13
    cs_serialized->num = cs->num;
1266
1267
13
    if (cs->num) {
1268
13
  leaves = FcCharSetLeaves (cs);
1269
13
  leaves_serialized = FcSerializePtr (serialize, leaves);
1270
13
  if (!leaves_serialized)
1271
0
      return NULL;
1272
1273
13
  cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
1274
13
                                                leaves_serialized);
1275
1276
13
  numbers = FcCharSetNumbers (cs);
1277
13
  numbers_serialized = FcSerializePtr (serialize, numbers);
1278
13
  if (!numbers)
1279
0
      return NULL;
1280
1281
13
  cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
1282
13
                                                 numbers_serialized);
1283
1284
288
  for (i = 0; i < cs->num; i++) {
1285
275
      leaf = FcCharSetLeaf (cs, i);
1286
275
      leaf_serialized = FcSerializePtr (serialize, leaf);
1287
275
      if (!leaf_serialized)
1288
0
    return NULL;
1289
275
      *leaf_serialized = *leaf;
1290
275
      leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
1291
275
                                            leaf_serialized);
1292
275
      numbers_serialized[i] = numbers[i];
1293
275
  }
1294
13
    } else {
1295
0
  cs_serialized->leaves_offset = 0;
1296
0
  cs_serialized->numbers_offset = 0;
1297
0
    }
1298
1299
13
    return cs_serialized;
1300
13
}
1301
#define __fccharset__
1302
#include "fcaliastail.h"
1303
#undef __fccharset__