Coverage Report

Created: 2026-02-10 07:39

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
1.70M
{
98
1.70M
    FcChar16 *numbers = FcCharSetNumbers (fcs);
99
1.70M
    FcChar16  page;
100
1.70M
    int       low = start;
101
1.70M
    int       high = fcs->num - 1;
102
103
1.70M
    if (!numbers)
104
0
  return -1;
105
8.54M
    while (low <= high) {
106
8.32M
  int mid = (low + high) >> 1;
107
8.32M
  page = numbers[mid];
108
8.32M
  if (page == num)
109
1.47M
      return mid;
110
6.84M
  if (page < num)
111
874k
      low = mid + 1;
112
5.97M
  else
113
5.97M
      high = mid - 1;
114
6.84M
    }
115
228k
    if (high < 0 || (high < fcs->num && numbers[high] < num))
116
228k
  high++;
117
228k
    return -(high + 1);
118
1.70M
}
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
1.70M
{
129
1.70M
    return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
130
1.70M
}
131
132
static FcCharLeaf *
133
FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
134
1.70M
{
135
1.70M
    int pos = FcCharSetFindLeafPos (fcs, ucs4);
136
1.70M
    if (pos >= 0)
137
1.47M
  return FcCharSetLeaf (fcs, pos);
138
228k
    return 0;
139
1.70M
}
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
      intptr_t    *new_leaves;
172
173
0
      alloced *= 2;
174
0
      numbers = realloc (numbers, alloced * sizeof (*numbers));
175
0
      if (!numbers)
176
0
    return FcFalse;
177
0
      new_leaves = realloc (leaves, alloced * sizeof (*leaves));
178
0
      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
0
      for (i = 0; i < fcs->num; i++) {
192
    // Reconstruct FcCharLeaf* from offset, similar to how FcCharSetLeaf() macro operates
193
0
    FcCharLeaf *leaf = FcOffsetToPtr (leaves, new_leaves[i], FcCharLeaf);
194
0
    new_leaves[i] = FcPtrToOffset (new_leaves, leaf);
195
0
      }
196
0
      leaves = new_leaves;
197
0
  }
198
199
0
  fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
200
0
  fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
201
0
    }
202
203
0
    memmove (leaves + pos + 1, leaves + pos,
204
0
             (fcs->num - pos) * sizeof (*leaves));
205
0
    memmove (numbers + pos + 1, numbers + pos,
206
0
             (fcs->num - pos) * sizeof (*numbers));
207
0
    numbers[pos] = (FcChar16)ucs4;
208
0
    leaves[pos] = FcPtrToOffset (leaves, leaf);
209
0
    fcs->num++;
210
0
    return FcTrue;
211
0
}
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
0
{
221
0
    int         pos;
222
0
    FcCharLeaf *leaf;
223
224
0
    pos = FcCharSetFindLeafPos (fcs, ucs4);
225
0
    if (pos >= 0)
226
0
  return FcCharSetLeaf (fcs, pos);
227
228
0
    leaf = calloc (1, sizeof (FcCharLeaf));
229
0
    if (!leaf)
230
0
  return 0;
231
232
0
    pos = -pos - 1;
233
0
    if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos)) {
234
0
  free (leaf);
235
0
  return 0;
236
0
    }
237
0
    return leaf;
238
0
}
239
240
static FcBool
241
FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
242
0
{
243
0
    int pos;
244
245
0
    pos = FcCharSetFindLeafPos (fcs, ucs4);
246
0
    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
0
    pos = -pos - 1;
253
0
    return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
254
0
}
255
256
FcBool
257
FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
258
0
{
259
0
    FcCharLeaf *leaf;
260
0
    FcChar32   *b;
261
262
0
    if (fcs == NULL || FcRefIsConst (&fcs->ref))
263
0
  return FcFalse;
264
0
    leaf = FcCharSetFindLeafCreate (fcs, ucs4);
265
0
    if (!leaf)
266
0
  return FcFalse;
267
0
    b = &leaf->map[(ucs4 & 0xff) >> 5];
268
0
    *b |= (1U << (ucs4 & 0x1f));
269
0
    return FcTrue;
270
0
}
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
0
{
306
0
    int pos = FcCharSetFindLeafPos (fcs, iter->ucs4);
307
308
0
    if (pos < 0) {
309
0
  pos = -pos - 1;
310
0
  if (pos == fcs->num) {
311
0
      iter->ucs4 = ~0;
312
0
      iter->leaf = 0;
313
0
      return;
314
0
  }
315
0
  iter->ucs4 = (FcChar32)FcCharSetNumbers (fcs)[pos] << 8;
316
0
    }
317
0
    iter->leaf = FcCharSetLeaf (fcs, pos);
318
0
    iter->pos = pos;
319
0
}
320
321
static void
322
FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
323
0
{
324
0
    int pos = iter->pos + 1;
325
0
    if (pos >= fcs->num) {
326
0
  iter->ucs4 = ~0;
327
0
  iter->leaf = 0;
328
0
    } else {
329
0
  iter->ucs4 = (FcChar32)FcCharSetNumbers (fcs)[pos] << 8;
330
0
  iter->leaf = FcCharSetLeaf (fcs, pos);
331
0
  iter->pos = pos;
332
0
    }
333
0
}
334
335
static void
336
FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
337
0
{
338
0
    iter->ucs4 = 0;
339
0
    iter->pos = 0;
340
0
    FcCharSetIterSet (fcs, iter);
341
0
}
342
343
FcCharSet *
344
FcCharSetCopy (FcCharSet *src)
345
0
{
346
0
    if (src) {
347
0
  if (!FcRefIsConst (&src->ref))
348
0
      FcRefInc (&src->ref);
349
0
  else
350
0
      FcCacheObjectReference (src);
351
0
    }
352
0
    return src;
353
0
}
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
1.70M
{
553
1.70M
    FcCharLeaf *leaf;
554
555
1.70M
    if (!fcs)
556
0
  return FcFalse;
557
1.70M
    leaf = FcCharSetFindLeaf (fcs, ucs4);
558
1.70M
    if (!leaf)
559
228k
  return FcFalse;
560
1.47M
    return (leaf->map[(ucs4 & 0xff) >> 5] & (1U << (ucs4 & 0x1f))) != 0;
561
1.70M
}
562
563
static FcChar32
564
FcCharSetPopCount (FcChar32 c1)
565
0
{
566
0
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
567
0
    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
0
}
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
0
{
609
0
    FcCharSetIter ai;
610
0
    FcChar32      count = 0;
611
612
0
    if (a) {
613
0
  for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai)) {
614
0
      int       i = 256 / 32;
615
0
      FcChar32 *am = ai.leaf->map;
616
617
0
      while (i--)
618
0
    count += FcCharSetPopCount (*am++);
619
0
  }
620
0
    }
621
0
    return count;
622
0
}
623
624
FcChar32
625
FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
626
0
{
627
0
    FcCharSetIter ai, bi;
628
0
    FcChar32      count = 0;
629
630
0
    if (a && b) {
631
0
  FcCharSetIterStart (a, &ai);
632
0
  FcCharSetIterStart (b, &bi);
633
0
  while (ai.leaf) {
634
0
      if (ai.ucs4 <= bi.ucs4) {
635
0
    FcChar32 *am = ai.leaf->map;
636
0
    int       i = 256 / 32;
637
0
    if (ai.ucs4 == bi.ucs4) {
638
0
        FcChar32 *bm = bi.leaf->map;
639
0
        while (i--)
640
0
      count += FcCharSetPopCount (*am++ & ~*bm++);
641
0
    } else {
642
0
        while (i--)
643
0
      count += FcCharSetPopCount (*am++);
644
0
    }
645
0
    FcCharSetIterNext (a, &ai);
646
0
      } else if (bi.leaf) {
647
0
    bi.ucs4 = ai.ucs4;
648
0
    FcCharSetIterSet (b, &bi);
649
0
      }
650
0
  }
651
0
    }
652
0
    return count;
653
0
}
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
0
#define FC_CHAR_LEAF_BLOCK     (4096 / sizeof (FcCharLeafEnt))
939
0
#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
0
#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
0
{
976
0
    if (!freezer->leaf_remain) {
977
0
  FcCharLeafEnt **newBlocks;
978
979
0
  freezer->leaf_block_count++;
980
0
  newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
981
0
  if (!newBlocks)
982
0
      return 0;
983
0
  freezer->leaf_blocks = newBlocks;
984
0
  freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count - 1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
985
0
  if (!freezer->current_block)
986
0
      return 0;
987
0
  freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
988
0
    }
989
0
    freezer->leaf_remain--;
990
0
    freezer->leaves_allocated++;
991
0
    return freezer->current_block++;
992
0
}
993
994
static FcChar32
995
FcCharLeafHash (FcCharLeaf *leaf)
996
0
{
997
0
    FcChar32 hash = 0;
998
0
    int      i;
999
1000
0
    for (i = 0; i < 256 / 32; i++)
1001
0
  hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
1002
0
    return hash;
1003
0
}
1004
1005
static FcCharLeaf *
1006
FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
1007
0
{
1008
0
    FcChar32        hash = FcCharLeafHash (leaf);
1009
0
    FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
1010
0
    FcCharLeafEnt  *ent;
1011
1012
0
    for (ent = *bucket; ent; ent = ent->next) {
1013
0
  if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
1014
0
      return &ent->leaf;
1015
0
    }
1016
1017
0
    ent = FcCharLeafEntCreate (freezer);
1018
0
    if (!ent)
1019
0
  return 0;
1020
0
    ent->leaf = *leaf;
1021
0
    ent->hash = hash;
1022
0
    ent->next = *bucket;
1023
0
    *bucket = ent;
1024
0
    return &ent->leaf;
1025
0
}
1026
1027
static FcChar32
1028
FcCharSetHash (FcCharSet *fcs)
1029
0
{
1030
0
    FcChar32 hash = 0;
1031
0
    int      i;
1032
1033
    /* hash in leaves */
1034
0
    for (i = 0; i < fcs->num; i++)
1035
0
  hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf (fcs, i));
1036
    /* hash in numbers */
1037
0
    for (i = 0; i < fcs->num; i++)
1038
0
  hash = ((hash << 1) | (hash >> 31)) ^ FcCharSetNumbers (fcs)[i];
1039
0
    return hash;
1040
0
}
1041
1042
static FcBool
1043
FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
1044
0
{
1045
0
    FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t)orig) % FC_CHAR_SET_HASH_SIZE];
1046
0
    FcCharSetOrigEnt  *ent;
1047
1048
0
    ent = malloc (sizeof (FcCharSetOrigEnt));
1049
0
    if (!ent)
1050
0
  return FcFalse;
1051
0
    ent->orig = orig;
1052
0
    ent->frozen = frozen;
1053
0
    ent->next = *bucket;
1054
0
    *bucket = ent;
1055
0
    return FcTrue;
1056
0
}
1057
1058
static FcCharSet *
1059
FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs)
1060
0
{
1061
0
    FcChar32       hash = FcCharSetHash (fcs);
1062
0
    FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
1063
0
    FcCharSetEnt  *ent;
1064
0
    int            size;
1065
0
    int            i;
1066
1067
0
    for (ent = *bucket; ent; ent = ent->next) {
1068
0
  if (ent->hash == hash &&
1069
0
      ent->set.num == fcs->num &&
1070
0
      !memcmp (FcCharSetNumbers (&ent->set),
1071
0
               FcCharSetNumbers (fcs),
1072
0
               fcs->num * sizeof (FcChar16))) {
1073
0
      FcBool ok = FcTrue;
1074
0
      int    i;
1075
1076
0
      for (i = 0; i < fcs->num; i++)
1077
0
    if (FcCharSetLeaf (&ent->set, i) != FcCharSetLeaf (fcs, i))
1078
0
        ok = FcFalse;
1079
0
      if (ok)
1080
0
    return &ent->set;
1081
0
  }
1082
0
    }
1083
1084
0
    size = (sizeof (FcCharSetEnt) +
1085
0
            fcs->num * sizeof (FcCharLeaf *) +
1086
0
            fcs->num * sizeof (FcChar16));
1087
0
    ent = malloc (size);
1088
0
    if (!ent)
1089
0
  return 0;
1090
1091
0
    freezer->charsets_allocated++;
1092
1093
0
    FcRefSetConst (&ent->set.ref);
1094
0
    ent->set.num = fcs->num;
1095
0
    if (fcs->num) {
1096
0
  intptr_t *ent_leaves;
1097
1098
0
  ent->set.leaves_offset = sizeof (ent->set);
1099
0
  ent->set.numbers_offset = (ent->set.leaves_offset +
1100
0
                             fcs->num * sizeof (intptr_t));
1101
1102
0
  ent_leaves = FcCharSetLeaves (&ent->set);
1103
0
  for (i = 0; i < fcs->num; i++)
1104
0
      ent_leaves[i] = FcPtrToOffset (ent_leaves,
1105
0
                                     FcCharSetLeaf (fcs, i));
1106
0
  memcpy (FcCharSetNumbers (&ent->set),
1107
0
          FcCharSetNumbers (fcs),
1108
0
          fcs->num * sizeof (FcChar16));
1109
0
    } else {
1110
0
  ent->set.leaves_offset = 0;
1111
0
  ent->set.numbers_offset = 0;
1112
0
    }
1113
1114
0
    ent->hash = hash;
1115
0
    ent->next = *bucket;
1116
0
    *bucket = ent;
1117
1118
0
    return &ent->set;
1119
0
}
1120
1121
static const FcCharSet *
1122
FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
1123
0
{
1124
0
    FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t)orig) % FC_CHAR_SET_HASH_SIZE];
1125
0
    FcCharSetOrigEnt  *ent;
1126
1127
0
    for (ent = *bucket; ent; ent = ent->next)
1128
0
  if (ent->orig == orig)
1129
0
      return ent->frozen;
1130
0
    return NULL;
1131
0
}
1132
1133
const FcCharSet *
1134
FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
1135
0
{
1136
0
    FcCharSet       *b;
1137
0
    const FcCharSet *n = 0;
1138
0
    FcCharLeaf      *l;
1139
0
    int              i;
1140
1141
0
    b = FcCharSetCreate();
1142
0
    if (!b)
1143
0
  goto bail0;
1144
0
    for (i = 0; i < fcs->num; i++) {
1145
0
  l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf (fcs, i));
1146
0
  if (!l)
1147
0
      goto bail1;
1148
0
  if (!FcCharSetInsertLeaf (b, FcCharSetNumbers (fcs)[i] << 8, l))
1149
0
      goto bail1;
1150
0
    }
1151
0
    n = FcCharSetFreezeBase (freezer, b);
1152
0
    if (!FcCharSetFreezeOrig (freezer, fcs, n)) {
1153
0
  n = NULL;
1154
0
  goto bail1;
1155
0
    }
1156
0
    freezer->charsets_seen++;
1157
0
    freezer->leaves_seen += fcs->num;
1158
0
bail1:
1159
0
    if (b->num)
1160
0
  free (FcCharSetLeaves (b));
1161
0
    if (b->num)
1162
0
  free (FcCharSetNumbers (b));
1163
0
    free (b);
1164
0
bail0:
1165
0
    return n;
1166
0
}
1167
1168
FcCharSetFreezer *
1169
FcCharSetFreezerCreate (void)
1170
0
{
1171
0
    FcCharSetFreezer *freezer;
1172
1173
0
    freezer = calloc (1, sizeof (FcCharSetFreezer));
1174
0
    return freezer;
1175
0
}
1176
1177
void
1178
FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
1179
0
{
1180
0
    int i;
1181
1182
0
    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
0
    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) {
1188
0
  FcCharSetEnt *ent, *next;
1189
0
  for (ent = freezer->set_hash_table[i]; ent; ent = next) {
1190
0
      next = ent->next;
1191
0
      free (ent);
1192
0
  }
1193
0
    }
1194
1195
0
    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) {
1196
0
  FcCharSetOrigEnt *ent, *next;
1197
0
  for (ent = freezer->orig_hash_table[i]; ent; ent = next) {
1198
0
      next = ent->next;
1199
0
      free (ent);
1200
0
  }
1201
0
    }
1202
1203
0
    for (i = 0; i < freezer->leaf_block_count; i++)
1204
0
  free (freezer->leaf_blocks[i]);
1205
1206
0
    free (freezer->leaf_blocks);
1207
0
    free (freezer);
1208
0
}
1209
1210
FcBool
1211
FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
1212
0
{
1213
0
    intptr_t *leaves;
1214
0
    FcChar16 *numbers;
1215
0
    int       i;
1216
1217
0
    if (!FcRefIsConst (&cs->ref)) {
1218
0
  if (!serialize->cs_freezer) {
1219
0
      serialize->cs_freezer = FcCharSetFreezerCreate();
1220
0
      if (!serialize->cs_freezer)
1221
0
    return FcFalse;
1222
0
  }
1223
0
  if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
1224
0
      return FcTrue;
1225
1226
0
  cs = FcCharSetFreeze (serialize->cs_freezer, cs);
1227
0
    }
1228
1229
0
    leaves = FcCharSetLeaves (cs);
1230
0
    numbers = FcCharSetNumbers (cs);
1231
1232
0
    if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
1233
0
  return FcFalse;
1234
0
    if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
1235
0
  return FcFalse;
1236
0
    if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
1237
0
  return FcFalse;
1238
0
    for (i = 0; i < cs->num; i++)
1239
0
  if (!FcSerializeAlloc (serialize, FcCharSetLeaf (cs, i),
1240
0
                         sizeof (FcCharLeaf)))
1241
0
      return FcFalse;
1242
0
    return FcTrue;
1243
0
}
1244
1245
FcCharSet *
1246
FcCharSetSerialize (FcSerialize *serialize, const FcCharSet *cs)
1247
0
{
1248
0
    FcCharSet  *cs_serialized;
1249
0
    intptr_t   *leaves, *leaves_serialized;
1250
0
    FcChar16   *numbers, *numbers_serialized;
1251
0
    FcCharLeaf *leaf, *leaf_serialized;
1252
0
    int         i;
1253
1254
0
    if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer) {
1255
0
  cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
1256
0
  if (!cs)
1257
0
      return NULL;
1258
0
    }
1259
1260
0
    cs_serialized = FcSerializePtr (serialize, cs);
1261
0
    if (!cs_serialized)
1262
0
  return NULL;
1263
1264
0
    FcRefSetConst (&cs_serialized->ref);
1265
0
    cs_serialized->num = cs->num;
1266
1267
0
    if (cs->num) {
1268
0
  leaves = FcCharSetLeaves (cs);
1269
0
  leaves_serialized = FcSerializePtr (serialize, leaves);
1270
0
  if (!leaves_serialized)
1271
0
      return NULL;
1272
1273
0
  cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
1274
0
                                                leaves_serialized);
1275
1276
0
  numbers = FcCharSetNumbers (cs);
1277
0
  numbers_serialized = FcSerializePtr (serialize, numbers);
1278
0
  if (!numbers)
1279
0
      return NULL;
1280
1281
0
  cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
1282
0
                                                 numbers_serialized);
1283
1284
0
  for (i = 0; i < cs->num; i++) {
1285
0
      leaf = FcCharSetLeaf (cs, i);
1286
0
      leaf_serialized = FcSerializePtr (serialize, leaf);
1287
0
      if (!leaf_serialized)
1288
0
    return NULL;
1289
0
      *leaf_serialized = *leaf;
1290
0
      leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
1291
0
                                            leaf_serialized);
1292
0
      numbers_serialized[i] = numbers[i];
1293
0
  }
1294
0
    } else {
1295
0
  cs_serialized->leaves_offset = 0;
1296
0
  cs_serialized->numbers_offset = 0;
1297
0
    }
1298
1299
0
    return cs_serialized;
1300
0
}
1301
#define __fccharset__
1302
#include "fcaliastail.h"
1303
#undef __fccharset__