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