Coverage Report

Created: 2026-08-25 06:40

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