Fix fc-cat documentation (bug 8935).
[platform/upstream/fontconfig.git] / src / fccharset.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fccharset.c,v 1.18 2002/08/22 07:36:44 keithp Exp $
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 static FcBool
456 FcCharSetSubtractLeaf (FcCharLeaf *result,
457                        const FcCharLeaf *al,
458                        const FcCharLeaf *bl)
459 {
460     int     i;
461     FcBool  nonempty = FcFalse;
462
463     for (i = 0; i < 256/32; i++)
464         if ((result->map[i] = al->map[i] & ~bl->map[i]))
465             nonempty = FcTrue;
466     return nonempty;
467 }
468
469 FcCharSet *
470 FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
471 {
472     return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
473 }
474
475 FcBool
476 FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
477 {
478     FcCharLeaf  *leaf = FcCharSetFindLeaf (fcs, ucs4);
479     if (!leaf)
480         return FcFalse;
481     return (leaf->map[(ucs4 & 0xff) >> 5] & (1 << (ucs4 & 0x1f))) != 0;
482 }
483
484 static FcChar32
485 FcCharSetPopCount (FcChar32 c1)
486 {
487     /* hackmem 169 */
488     FcChar32    c2 = (c1 >> 1) & 033333333333;
489     c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
490     return (((c2 + (c2 >> 3)) & 030707070707) % 077);
491 }
492
493 FcChar32
494 FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
495 {
496     FcCharSetIter   ai, bi;
497     FcChar32        count = 0;
498     
499     FcCharSetIterStart (a, &ai);
500     FcCharSetIterStart (b, &bi);
501     while (ai.leaf && bi.leaf)
502     {
503         if (ai.ucs4 == bi.ucs4)
504         {
505             FcChar32    *am = ai.leaf->map;
506             FcChar32    *bm = bi.leaf->map;
507             int         i = 256/32;
508             while (i--)
509                 count += FcCharSetPopCount (*am++ & *bm++);
510             FcCharSetIterNext (a, &ai);
511         } 
512         else if (ai.ucs4 < bi.ucs4)
513         {
514             ai.ucs4 = bi.ucs4;
515             FcCharSetIterSet (a, &ai);
516         }
517         if (bi.ucs4 < ai.ucs4)
518         {
519             bi.ucs4 = ai.ucs4;
520             FcCharSetIterSet (b, &bi);
521         }
522     }
523     return count;
524 }
525
526 FcChar32
527 FcCharSetCount (const FcCharSet *a)
528 {
529     FcCharSetIter   ai;
530     FcChar32        count = 0;
531     
532     for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
533     {
534         int                 i = 256/32;
535         FcChar32            *am = ai.leaf->map;
536
537         while (i--)
538             count += FcCharSetPopCount (*am++);
539     }
540     return count;
541 }
542
543 FcChar32
544 FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
545 {
546     FcCharSetIter   ai, bi;
547     FcChar32        count = 0;
548     
549     FcCharSetIterStart (a, &ai);
550     FcCharSetIterStart (b, &bi);
551     while (ai.leaf)
552     {
553         if (ai.ucs4 <= bi.ucs4)
554         {
555             FcChar32    *am = ai.leaf->map;
556             int         i = 256/32;
557             if (ai.ucs4 == bi.ucs4)
558             {
559                 FcChar32        *bm = bi.leaf->map;
560                 while (i--)
561                     count += FcCharSetPopCount (*am++ & ~*bm++);
562             }
563             else
564             {
565                 while (i--)
566                     count += FcCharSetPopCount (*am++);
567             }
568             FcCharSetIterNext (a, &ai);
569         }
570         else if (bi.leaf)
571         {
572             bi.ucs4 = ai.ucs4;
573             FcCharSetIterSet (b, &bi);
574         }
575     }
576     return count;
577 }
578
579 /*
580  * return FcTrue iff a is a subset of b
581  */
582 FcBool
583 FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
584 {
585     int         ai, bi;
586     FcChar16    an, bn;
587     
588     if (a == b) return FcTrue;
589     bi = 0;
590     ai = 0;
591     while (ai < a->num && bi < b->num)
592     {
593         an = FcCharSetNumbers(a)[ai];
594         bn = FcCharSetNumbers(b)[bi];
595         /*
596          * Check matching pages
597          */
598         if (an == bn)
599         {
600             FcChar32    *am = FcCharSetLeaf(a, ai)->map;
601             FcChar32    *bm = FcCharSetLeaf(b, bi)->map;
602             
603             if (am != bm)
604             {
605                 int     i = 256/32;
606                 /*
607                  * Does am have any bits not in bm?
608                  */
609                 while (i--)
610                     if (*am++ & ~*bm++)
611                         return FcFalse;
612             }
613             ai++;
614             bi++;
615         }
616         /*
617          * Does a have any pages not in b?
618          */
619         else if (an < bn)
620             return FcFalse;
621         else
622         {
623             int     low = bi + 1;
624             int     high = b->num - 1;
625
626             /*
627              * Search for page 'an' in 'b'
628              */
629             while (low <= high)
630             {
631                 int mid = (low + high) >> 1;
632                 bn = FcCharSetNumbers(b)[mid];
633                 if (bn == an)
634                 {
635                     high = mid;
636                     break;
637                 }
638                 if (bn < an)
639                     low = mid + 1;
640                 else
641                     high = mid - 1;
642             }
643             bi = high;
644             while (bi < b->num && FcCharSetNumbers(b)[bi] < an)
645                 bi++;
646         }
647     }
648     /*
649      * did we look at every page?
650      */
651     return ai >= a->num;
652 }
653
654 /*
655  * These two functions efficiently walk the entire charmap for
656  * other software (like pango) that want their own copy
657  */
658
659 FcChar32
660 FcCharSetNextPage (const FcCharSet  *a, 
661                    FcChar32         map[FC_CHARSET_MAP_SIZE],
662                    FcChar32         *next)
663 {
664     FcCharSetIter   ai;
665     FcChar32        page;
666
667     ai.ucs4 = *next;
668     FcCharSetIterSet (a, &ai);
669     if (!ai.leaf)
670         return FC_CHARSET_DONE;
671     
672     /*
673      * Save current information
674      */
675     page = ai.ucs4;
676     memcpy (map, ai.leaf->map, sizeof (ai.leaf->map));
677     /*
678      * Step to next page
679      */
680     FcCharSetIterNext (a, &ai);
681     *next = ai.ucs4;
682
683     return page;
684 }
685
686 FcChar32
687 FcCharSetFirstPage (const FcCharSet *a, 
688                     FcChar32        map[FC_CHARSET_MAP_SIZE],
689                     FcChar32        *next)
690 {
691     *next = 0;
692     return FcCharSetNextPage (a, map, next);
693 }
694
695 /*
696  * old coverage API, rather hard to use correctly
697  */
698     
699 FcChar32
700 FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result)
701 {
702     FcCharSetIter   ai;
703
704     ai.ucs4 = page;
705     FcCharSetIterSet (a, &ai);
706     if (!ai.leaf)
707     {
708         memset (result, '\0', 256 / 8);
709         page = 0;
710     }
711     else
712     {
713         memcpy (result, ai.leaf->map, sizeof (ai.leaf->map));
714         FcCharSetIterNext (a, &ai);
715         page = ai.ucs4;
716     }
717     return page;
718 }
719
720 /*
721  * ASCII representation of charsets.
722  * 
723  * Each leaf is represented as 9 32-bit values, the code of the first character followed
724  * by 8 32 bit values for the leaf itself.  Each value is encoded as 5 ASCII characters,
725  * only 85 different values are used to avoid control characters as well as the other
726  * characters used to encode font names.  85**5 > 2^32 so things work out, but
727  * it's not exactly human readable output.  As a special case, 0 is encoded as a space
728  */
729
730 static const unsigned char      charToValue[256] = {
731     /*     "" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
732     /*   "\b" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
733     /* "\020" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
734     /* "\030" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
735     /*    " " */ 0xff,  0x00,  0xff,  0x01,  0x02,  0x03,  0x04,  0xff, 
736     /*    "(" */ 0x05,  0x06,  0x07,  0x08,  0xff,  0xff,  0x09,  0x0a, 
737     /*    "0" */ 0x0b,  0x0c,  0x0d,  0x0e,  0x0f,  0x10,  0x11,  0x12, 
738     /*    "8" */ 0x13,  0x14,  0xff,  0x15,  0x16,  0xff,  0x17,  0x18, 
739     /*    "@" */ 0x19,  0x1a,  0x1b,  0x1c,  0x1d,  0x1e,  0x1f,  0x20, 
740     /*    "H" */ 0x21,  0x22,  0x23,  0x24,  0x25,  0x26,  0x27,  0x28, 
741     /*    "P" */ 0x29,  0x2a,  0x2b,  0x2c,  0x2d,  0x2e,  0x2f,  0x30, 
742     /*    "X" */ 0x31,  0x32,  0x33,  0x34,  0xff,  0x35,  0x36,  0xff, 
743     /*    "`" */ 0xff,  0x37,  0x38,  0x39,  0x3a,  0x3b,  0x3c,  0x3d, 
744     /*    "h" */ 0x3e,  0x3f,  0x40,  0x41,  0x42,  0x43,  0x44,  0x45, 
745     /*    "p" */ 0x46,  0x47,  0x48,  0x49,  0x4a,  0x4b,  0x4c,  0x4d, 
746     /*    "x" */ 0x4e,  0x4f,  0x50,  0x51,  0x52,  0x53,  0x54,  0xff, 
747     /* "\200" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
748     /* "\210" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
749     /* "\220" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
750     /* "\230" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
751     /* "\240" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
752     /* "\250" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
753     /* "\260" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
754     /* "\270" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
755     /* "\300" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
756     /* "\310" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
757     /* "\320" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
758     /* "\330" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
759     /* "\340" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
760     /* "\350" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
761     /* "\360" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
762     /* "\370" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
763 };
764
765 static const FcChar8 valueToChar[0x55] = {
766     /* 0x00 */ '!', '#', '$', '%', '&', '(', ')', '*',
767     /* 0x08 */ '+', '.', '/', '0', '1', '2', '3', '4',
768     /* 0x10 */ '5', '6', '7', '8', '9', ';', '<', '>',
769     /* 0x18 */ '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
770     /* 0x20 */ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
771     /* 0x28 */ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
772     /* 0x30 */ 'W', 'X', 'Y', 'Z', '[', ']', '^', 'a',
773     /* 0x38 */ 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
774     /* 0x40 */ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
775     /* 0x48 */ 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
776     /* 0x50 */ 'z', '{', '|', '}', '~',
777 };
778
779 static FcChar8 *
780 FcCharSetParseValue (FcChar8 *string, FcChar32 *value)
781 {
782     int         i;
783     FcChar32    v;
784     FcChar32    c;
785     
786     if (*string == ' ')
787     {
788         v = 0;
789         string++;
790     }
791     else
792     {
793         v = 0;
794         for (i = 0; i < 5; i++)
795         {
796             if (!(c = (FcChar32) (unsigned char) *string++))
797                 return 0;
798             c = charToValue[c];
799             if (c == 0xff)
800                 return 0;
801             v = v * 85 + c;
802         }
803     }
804     *value = v;
805     return string;
806 }
807
808 static FcBool
809 FcCharSetUnparseValue (FcStrBuf *buf, FcChar32 value)
810 {
811     int     i;
812     if (value == 0)
813     {
814         return FcStrBufChar (buf, ' ');
815     }
816     else
817     {
818         FcChar8 string[6];
819         FcChar8 *s = string + 5;
820         string[5] = '\0';
821         for (i = 0; i < 5; i++)
822         {
823             *--s = valueToChar[value % 85];
824             value /= 85;
825         }
826         for (i = 0; i < 5; i++)
827             if (!FcStrBufChar (buf, *s++))
828                 return FcFalse;
829     }
830     return FcTrue;
831 }
832
833 FcCharSet *
834 FcNameParseCharSet (FcChar8 *string)
835 {
836     FcCharSet   *c;
837     FcChar32    ucs4;
838     FcCharLeaf  *leaf;
839     FcCharLeaf  temp;
840     FcChar32    bits;
841     int         i;
842
843     c = FcCharSetCreate ();
844     if (!c)
845         goto bail0;
846     while (*string)
847     {
848         string = FcCharSetParseValue (string, &ucs4);
849         if (!string)
850             goto bail1;
851         bits = 0;
852         for (i = 0; i < 256/32; i++)
853         {
854             string = FcCharSetParseValue (string, &temp.map[i]);
855             if (!string)
856                 goto bail1;
857             bits |= temp.map[i];
858         }
859         if (bits)
860         {
861             leaf = malloc (sizeof (FcCharLeaf));
862             if (!leaf)
863                 goto bail1;
864             *leaf = temp;
865             if (!FcCharSetInsertLeaf (c, ucs4, leaf))
866                 goto bail1;
867         }
868     }
869     return c;
870 bail1:
871     if (c->num)
872     {
873         FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *));
874         free (FcCharSetLeaves (c));
875     }
876     if (c->num)
877     {
878         FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16));
879         free (FcCharSetNumbers (c));
880     }
881     FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
882     free (c);
883 bail0:
884     return NULL;
885 }
886
887 FcBool
888 FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
889 {
890     FcCharSetIter   ci;
891     int             i;
892 #ifdef CHECK
893     int             len = buf->len;
894 #endif
895
896     for (FcCharSetIterStart (c, &ci);
897          ci.leaf;
898          FcCharSetIterNext (c, &ci))
899     {
900         if (!FcCharSetUnparseValue (buf, ci.ucs4))
901             return FcFalse;
902         for (i = 0; i < 256/32; i++)
903             if (!FcCharSetUnparseValue (buf, ci.leaf->map[i]))
904                 return FcFalse;
905     }
906 #ifdef CHECK
907     {
908         FcCharSet       *check;
909         FcChar32        missing;
910         FcCharSetIter   ci, checki;
911         
912         /* null terminate for parser */
913         FcStrBufChar (buf, '\0');
914         /* step back over null for life after test */
915         buf->len--;
916         check = FcNameParseCharSet (buf->buf + len);
917         FcCharSetIterStart (c, &ci);
918         FcCharSetIterStart (check, &checki);
919         while (ci.leaf || checki.leaf)
920         {
921             if (ci.ucs4 < checki.ucs4)
922             {
923                 printf ("Missing leaf node at 0x%x\n", ci.ucs4);
924                 FcCharSetIterNext (c, &ci);
925             }
926             else if (checki.ucs4 < ci.ucs4)
927             {
928                 printf ("Extra leaf node at 0x%x\n", checki.ucs4);
929                 FcCharSetIterNext (check, &checki);
930             }
931             else
932             {
933                 int         i = 256/32;
934                 FcChar32    *cm = ci.leaf->map;
935                 FcChar32    *checkm = checki.leaf->map;
936
937                 for (i = 0; i < 256; i += 32)
938                 {
939                     if (*cm != *checkm)
940                         printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
941                                 ci.ucs4 + i, *cm, *checkm);
942                     cm++;
943                     checkm++;
944                 }
945                 FcCharSetIterNext (c, &ci);
946                 FcCharSetIterNext (check, &checki);
947             }
948         }
949         if ((missing = FcCharSetSubtractCount (c, check)))
950             printf ("%d missing in reparsed result\n", missing);
951         if ((missing = FcCharSetSubtractCount (check, c)))
952             printf ("%d extra in reparsed result\n", missing);
953         FcCharSetDestroy (check);
954     }
955 #endif
956     
957     return FcTrue;
958 }
959
960 typedef struct _FcCharLeafEnt FcCharLeafEnt;
961
962 struct _FcCharLeafEnt {
963     FcCharLeafEnt   *next;
964     FcChar32        hash;
965     FcCharLeaf      leaf;
966 };
967
968 #define FC_CHAR_LEAF_BLOCK      (4096 / sizeof (FcCharLeafEnt))
969 #define FC_CHAR_LEAF_HASH_SIZE  257
970
971 typedef struct _FcCharSetEnt FcCharSetEnt;
972
973 struct _FcCharSetEnt {
974     FcCharSetEnt        *next;
975     FcChar32            hash;
976     FcCharSet           set;
977 };
978
979 typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
980
981 struct _FcCharSetOrigEnt {
982     FcCharSetOrigEnt    *next;
983     const FcCharSet     *orig;
984     const FcCharSet     *frozen;
985 };
986
987 #define FC_CHAR_SET_HASH_SIZE    67
988
989 struct _FcCharSetFreezer {
990     FcCharLeafEnt   *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE];
991     FcCharLeafEnt   **leaf_blocks;
992     int             leaf_block_count;
993     FcCharSetEnt    *set_hash_table[FC_CHAR_SET_HASH_SIZE];
994     FcCharSetOrigEnt    *orig_hash_table[FC_CHAR_SET_HASH_SIZE];
995     FcCharLeafEnt   *current_block;
996     int             leaf_remain;
997     int             leaves_seen;
998     int             charsets_seen;
999     int             leaves_allocated;
1000     int             charsets_allocated;
1001 };
1002
1003 static FcCharLeafEnt *
1004 FcCharLeafEntCreate (FcCharSetFreezer *freezer)
1005 {
1006     if (!freezer->leaf_remain)
1007     {
1008         FcCharLeafEnt **newBlocks;
1009
1010         freezer->leaf_block_count++;
1011         newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
1012         if (!newBlocks)
1013             return 0;
1014         freezer->leaf_blocks = newBlocks;
1015         freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
1016         if (!freezer->current_block)
1017             return 0;
1018         FcMemAlloc (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
1019         freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
1020     }
1021     freezer->leaf_remain--;
1022     freezer->leaves_allocated++;
1023     return freezer->current_block++;
1024 }
1025
1026 static FcChar32
1027 FcCharLeafHash (FcCharLeaf *leaf)
1028 {
1029     FcChar32    hash = 0;
1030     int         i;
1031
1032     for (i = 0; i < 256/32; i++)
1033         hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
1034     return hash;
1035 }
1036
1037 static FcCharLeaf *
1038 FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
1039 {
1040     FcChar32                    hash = FcCharLeafHash (leaf);
1041     FcCharLeafEnt               **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
1042     FcCharLeafEnt               *ent;
1043     
1044     for (ent = *bucket; ent; ent = ent->next)
1045     {
1046         if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
1047             return &ent->leaf;
1048     }
1049
1050     ent = FcCharLeafEntCreate(freezer);
1051     if (!ent)
1052         return 0;
1053     ent->leaf = *leaf;
1054     ent->hash = hash;
1055     ent->next = *bucket;
1056     *bucket = ent;
1057     return &ent->leaf;
1058 }
1059
1060 static FcChar32
1061 FcCharSetHash (FcCharSet *fcs)
1062 {
1063     FcChar32    hash = 0;
1064     int         i;
1065
1066     /* hash in leaves */
1067     for (i = 0; i < fcs->num; i++)
1068         hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf(fcs,i));
1069     /* hash in numbers */
1070     for (i = 0; i < fcs->num; i++)
1071         hash = ((hash << 1) | (hash >> 31)) ^ *FcCharSetNumbers(fcs);
1072     return hash;
1073 }
1074
1075 static FcBool
1076 FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
1077 {
1078     FcCharSetOrigEnt    **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE];
1079     FcCharSetOrigEnt    *ent;
1080     
1081     ent = malloc (sizeof (FcCharSetOrigEnt));
1082     if (!ent)
1083         return FcFalse;
1084     ent->orig = orig;
1085     ent->frozen = frozen;
1086     ent->next = *bucket;
1087     *bucket = ent;
1088     return FcTrue;
1089 }
1090
1091 static FcCharSet *
1092 FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet *orig)
1093 {
1094     FcChar32            hash = FcCharSetHash (fcs);
1095     FcCharSetEnt        **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
1096     FcCharSetEnt        *ent;
1097     int                 size;
1098     int                 i;
1099
1100     for (ent = *bucket; ent; ent = ent->next)
1101     {
1102         if (ent->hash == hash &&
1103             ent->set.num == fcs->num &&
1104             !memcmp (FcCharSetNumbers(&ent->set), 
1105                      FcCharSetNumbers(fcs),
1106                      fcs->num * sizeof (FcChar16)))
1107         {
1108             FcBool ok = FcTrue;
1109             int i;
1110
1111             for (i = 0; i < fcs->num; i++)
1112                 if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
1113                     ok = FcFalse;
1114             if (ok)
1115                 return &ent->set;
1116         }
1117     }
1118
1119     size = (sizeof (FcCharSetEnt) +
1120             fcs->num * sizeof (FcCharLeaf *) +
1121             fcs->num * sizeof (FcChar16));
1122     ent = malloc (size);
1123     if (!ent)
1124         return 0;
1125     FcMemAlloc (FC_MEM_CHARSET, size);
1126     
1127     freezer->charsets_allocated++;
1128     
1129     ent->set.ref = FC_REF_CONSTANT;
1130     ent->set.num = fcs->num;
1131     if (fcs->num)
1132     {
1133         intptr_t    *ent_leaves;
1134
1135         ent->set.leaves_offset = sizeof (ent->set);
1136         ent->set.numbers_offset = (ent->set.leaves_offset +
1137                                    fcs->num * sizeof (intptr_t));
1138     
1139         ent_leaves = FcCharSetLeaves (&ent->set);
1140         for (i = 0; i < fcs->num; i++)
1141             ent_leaves[i] = FcPtrToOffset (ent_leaves,
1142                                            FcCharSetLeaf (fcs, i));
1143         memcpy (FcCharSetNumbers (&ent->set), 
1144                 FcCharSetNumbers (fcs), 
1145                 fcs->num * sizeof (FcChar16));
1146     }
1147     else
1148     {
1149         ent->set.leaves_offset = 0;
1150         ent->set.numbers_offset = 0;
1151     }
1152
1153     ent->hash = hash;
1154     ent->next = *bucket;
1155     *bucket = ent;
1156
1157     return &ent->set;
1158 }
1159
1160 static const FcCharSet *
1161 FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
1162 {
1163     FcCharSetOrigEnt    **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE];
1164     FcCharSetOrigEnt    *ent;
1165     
1166     for (ent = *bucket; ent; ent = ent->next)
1167         if (ent->orig == orig)
1168             return ent->frozen;
1169     return NULL;
1170 }
1171
1172 const FcCharSet *
1173 FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
1174 {
1175     FcCharSet       *b;
1176     const FcCharSet *n = 0;
1177     FcCharLeaf      *l;
1178     int             i;
1179
1180     b = FcCharSetCreate ();
1181     if (!b)
1182         goto bail0;
1183     for (i = 0; i < fcs->num; i++)
1184     {
1185         l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i));
1186         if (!l)
1187             goto bail1;
1188         if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l))
1189             goto bail1;
1190     }
1191     n = FcCharSetFreezeBase (freezer, b, fcs);
1192     if (!FcCharSetFreezeOrig (freezer, fcs, n))
1193     {
1194         n = NULL;
1195         goto bail1;
1196     }
1197     freezer->charsets_seen++;
1198     freezer->leaves_seen += fcs->num;
1199 bail1:
1200     if (b->num)
1201     {
1202         FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *));
1203         free (FcCharSetLeaves (b));
1204     }
1205     if (b->num)
1206     {
1207         FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16));
1208         free (FcCharSetNumbers (b));
1209     }
1210     FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
1211     free (b);
1212 bail0:
1213     return n;
1214 }
1215
1216 FcCharSetFreezer *
1217 FcCharSetFreezerCreate (void)
1218 {
1219     FcCharSetFreezer    *freezer;
1220
1221     freezer = calloc (1, sizeof (FcCharSetFreezer));
1222     return freezer;
1223 }
1224
1225 void
1226 FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
1227 {
1228     int i;
1229
1230     if (FcDebug() & FC_DBG_CACHE)
1231     {
1232         printf ("\ncharsets %d -> %d leaves %d -> %d\n",
1233                 freezer->charsets_seen, freezer->charsets_allocated,
1234                 freezer->leaves_seen, freezer->leaves_allocated);
1235     }
1236     for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
1237     {
1238         FcCharSetEnt    *ent, *next;
1239         for (ent = freezer->set_hash_table[i]; ent; ent = next)
1240         {
1241             next = ent->next;
1242             free (ent);
1243         }
1244     }
1245
1246     for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
1247     {
1248         FcCharSetOrigEnt        *ent, *next;
1249         for (ent = freezer->orig_hash_table[i]; ent; ent = next)
1250         {
1251             next = ent->next;
1252             free (ent);
1253         }
1254     }
1255
1256     for (i = 0; i < freezer->leaf_block_count; i++)
1257         free (freezer->leaf_blocks[i]);
1258
1259     free (freezer->leaf_blocks);
1260     free (freezer);
1261 }
1262
1263 FcBool
1264 FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
1265 {
1266     intptr_t        *leaves;
1267     FcChar16        *numbers;
1268     int             i;
1269     
1270     if (cs->ref != FC_REF_CONSTANT)
1271     {
1272         if (!serialize->cs_freezer)
1273         {
1274             serialize->cs_freezer = FcCharSetFreezerCreate ();
1275             if (!serialize->cs_freezer)
1276                 return FcFalse;
1277         }
1278         if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
1279             return FcTrue;
1280     
1281         cs = FcCharSetFreeze (serialize->cs_freezer, cs);
1282     }
1283     
1284     leaves = FcCharSetLeaves (cs);
1285     numbers = FcCharSetNumbers (cs);
1286     
1287     if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
1288         return FcFalse;
1289     if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
1290         return FcFalse;
1291     if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
1292         return FcFalse;
1293     for (i = 0; i < cs->num; i++)
1294         if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i),
1295                                sizeof (FcCharLeaf)))
1296             return FcFalse;
1297     return FcTrue;
1298 }
1299     
1300 FcCharSet *
1301 FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
1302 {
1303     FcCharSet   *cs_serialized;
1304     intptr_t    *leaves, *leaves_serialized;
1305     FcChar16    *numbers, *numbers_serialized;
1306     FcCharLeaf  *leaf, *leaf_serialized;
1307     int         i;
1308
1309     if (cs->ref != FC_REF_CONSTANT && serialize->cs_freezer)
1310     {
1311         cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
1312         if (!cs)
1313             return NULL;
1314     }
1315                     
1316     cs_serialized = FcSerializePtr (serialize, cs);
1317     if (!cs_serialized)
1318         return NULL;
1319     
1320     cs_serialized->ref = FC_REF_CONSTANT;
1321     cs_serialized->num = cs->num;
1322
1323     if (cs->num)
1324     {
1325         leaves = FcCharSetLeaves (cs);
1326         leaves_serialized = FcSerializePtr (serialize, leaves);
1327         if (!leaves_serialized)
1328             return NULL;
1329     
1330         cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
1331                                                       leaves_serialized);
1332         
1333         numbers = FcCharSetNumbers (cs);
1334         numbers_serialized = FcSerializePtr (serialize, numbers);
1335         if (!numbers)
1336             return NULL;
1337     
1338         cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
1339                                                        numbers_serialized);
1340     
1341         for (i = 0; i < cs->num; i++)
1342         {
1343             leaf = FcCharSetLeaf (cs, i);
1344             leaf_serialized = FcSerializePtr (serialize, leaf);
1345             if (!leaf_serialized)
1346                 return NULL;
1347             *leaf_serialized = *leaf;
1348             leaves_serialized[i] = FcPtrToOffset (leaves_serialized, 
1349                                                   leaf_serialized);
1350             numbers_serialized[i] = numbers[i];
1351         }
1352     }
1353     else
1354     {
1355         cs_serialized->leaves_offset = 0;
1356         cs_serialized->numbers_offset = 0;
1357     }
1358     
1359     return cs_serialized;
1360 }
1361 #define __fccharset__
1362 #include "fcaliastail.h"
1363 #undef __fccharset__