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