2 * $RCSId: xc/lib/fontconfig/src/fccharset.c,v 1.18 2002/08/22 07:36:44 keithp Exp $
4 * Copyright © 2001 Keith Packard
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.
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.
33 static FcCharSet
* charsets
= 0;
34 static FcChar16
* numbers
= 0;
35 static int charset_ptr
, charset_count
;
36 static int charset_numbers_ptr
, charset_numbers_count
;
37 static FcCharLeaf
* leaves
= 0;
38 static int charset_leaf_ptr
, charset_leaf_count
;
39 static int * leaf_idx
= 0;
40 static int charset_leaf_idx_ptr
, charset_leaf_idx_count
;
43 FcCharSetClearStatic()
47 charset_ptr
= 0; charset_count
= 0;
49 charset_leaf_ptr
= 0; charset_leaf_count
= 0;
51 charset_leaf_idx_ptr
= 0; charset_leaf_idx_count
= 0;
55 FcCharSetCreate (void)
59 fcs
= (FcCharSet
*) malloc (sizeof (FcCharSet
));
62 FcMemAlloc (FC_MEM_CHARSET
, sizeof (FcCharSet
));
65 fcs
->storage
= FcStorageDynamic
;
66 fcs
->u
.dyn
.leaves
= 0;
67 fcs
->u
.dyn
.numbers
= 0;
77 return FcCharSetCreate ();
81 FcCharSetPtrDestroy (FcCharSetPtr fcs
)
83 FcCharSetDestroy (FcCharSetPtrU(fcs
));
84 if (fcs
.storage
== FcStorageDynamic
&&
85 FcCharSetPtrU(fcs
)->ref
!= FC_REF_CONSTANT
)
88 FcMemFree (FC_MEM_CHARSET
, sizeof(FcCharSet
));
93 FcCharSetDestroy (FcCharSet
*fcs
)
96 if (fcs
->ref
== FC_REF_CONSTANT
)
100 if (fcs
->storage
== FcStorageDynamic
)
102 for (i
= 0; i
< fcs
->num
; i
++)
104 FcMemFree (FC_MEM_CHARLEAF
, sizeof (FcCharLeaf
));
105 free (fcs
->u
.dyn
.leaves
[i
]);
107 if (fcs
->u
.dyn
.leaves
)
109 FcMemFree (FC_MEM_CHARSET
, fcs
->num
* sizeof (FcCharLeaf
*));
110 free (fcs
->u
.dyn
.leaves
);
112 if (fcs
->u
.dyn
.numbers
)
114 FcMemFree (FC_MEM_CHARSET
, fcs
->num
* sizeof (FcChar16
));
115 free (fcs
->u
.dyn
.numbers
);
118 FcMemFree (FC_MEM_CHARSET
, sizeof (FcCharSet
));
123 * Locate the leaf containing the specified char, return
124 * its index if it exists, otherwise return negative of
125 * the (position + 1) where it should be inserted
129 FcCharSetFindLeafPos (const FcCharSet
*fcs
, FcChar32 ucs4
)
131 FcChar16
*numbers
= FcCharSetGetNumbers(fcs
);
134 int high
= fcs
->num
- 1;
141 int mid
= (low
+ high
) >> 1;
150 if (high
< 0 || (high
< fcs
->num
&& numbers
[high
] < ucs4
))
156 FcCharSetFindLeaf (const FcCharSet
*fcs
, FcChar32 ucs4
)
158 int pos
= FcCharSetFindLeafPos (fcs
, ucs4
);
160 return FcCharSetGetLeaf(fcs
, pos
);
165 FcCharSetPutLeaf (FcCharSet
*fcs
,
176 if (fcs
->storage
== FcStorageStatic
)
180 leaves
= malloc ((fcs
->num
+ 1) * sizeof (FcCharLeaf
*));
183 FcMemAlloc (FC_MEM_CHARSET
, (fcs
->num
+ 1) * sizeof (FcCharLeaf
*));
184 numbers
= malloc ((fcs
->num
+ 1) * sizeof (FcChar16
));
187 FcMemAlloc (FC_MEM_CHARSET
, (fcs
->num
+ 1) * sizeof (FcChar16
));
189 for (i
= 0; i
< fcs
->num
; i
++)
190 leaves
[i
] = FcCharSetGetLeaf(fcs
, i
);
191 memcpy (numbers
, FcCharSetGetNumbers(fcs
),
192 fcs
->num
* sizeof (FcChar16
));
193 fcs
->storage
= FcStorageDynamic
;
197 if (!fcs
->u
.dyn
.leaves
)
198 leaves
= malloc (sizeof (FcCharLeaf
*));
200 leaves
= realloc (fcs
->u
.dyn
.leaves
, (fcs
->num
+ 1) * sizeof (FcCharLeaf
*));
204 FcMemFree (FC_MEM_CHARSET
, fcs
->num
* sizeof (FcCharLeaf
*));
205 FcMemAlloc (FC_MEM_CHARSET
, (fcs
->num
+ 1) * sizeof (FcCharLeaf
*));
206 fcs
->u
.dyn
.leaves
= leaves
;
207 if (!fcs
->u
.dyn
.numbers
)
208 numbers
= malloc (sizeof (FcChar16
));
210 numbers
= realloc (fcs
->u
.dyn
.numbers
, (fcs
->num
+ 1) * sizeof (FcChar16
));
214 FcMemFree (FC_MEM_CHARSET
, fcs
->num
* sizeof (FcChar16
));
215 FcMemAlloc (FC_MEM_CHARSET
, (fcs
->num
+ 1) * sizeof (FcChar16
));
216 fcs
->u
.dyn
.numbers
= numbers
;
219 memmove (fcs
->u
.dyn
.leaves
+ pos
+ 1, fcs
->u
.dyn
.leaves
+ pos
,
220 (fcs
->num
- pos
) * sizeof (FcCharLeaf
*));
221 memmove (fcs
->u
.dyn
.numbers
+ pos
+ 1, fcs
->u
.dyn
.numbers
+ pos
,
222 (fcs
->num
- pos
) * sizeof (FcChar16
));
223 fcs
->u
.dyn
.numbers
[pos
] = (FcChar16
) ucs4
;
224 fcs
->u
.dyn
.leaves
[pos
] = leaf
;
230 * Locate the leaf containing the specified char, creating it
235 FcCharSetFindLeafCreate (FcCharSet
*fcs
, FcChar32 ucs4
)
240 pos
= FcCharSetFindLeafPos (fcs
, ucs4
);
242 return FcCharSetGetLeaf(fcs
, pos
);
244 leaf
= calloc (1, sizeof (FcCharLeaf
));
249 if (!FcCharSetPutLeaf (fcs
, ucs4
, leaf
, pos
))
254 FcMemAlloc (FC_MEM_CHARLEAF
, sizeof (FcCharLeaf
));
259 FcCharSetInsertLeaf (FcCharSet
*fcs
, FcChar32 ucs4
, FcCharLeaf
*leaf
)
263 pos
= FcCharSetFindLeafPos (fcs
, ucs4
);
266 FcMemFree (FC_MEM_CHARLEAF
, sizeof (FcCharLeaf
));
267 if (fcs
->storage
== FcStorageDynamic
)
269 free (fcs
->u
.dyn
.leaves
[pos
]);
270 fcs
->u
.dyn
.leaves
[pos
] = leaf
;
274 leaves
[leaf_idx
[fcs
->u
.stat
.leafidx_offset
]+pos
] = *leaf
;
279 return FcCharSetPutLeaf (fcs
, ucs4
, leaf
, pos
);
283 FcCharSetAddChar (FcCharSet
*fcs
, FcChar32 ucs4
)
288 if (fcs
->ref
== FC_REF_CONSTANT
)
290 leaf
= FcCharSetFindLeafCreate (fcs
, ucs4
);
293 b
= &leaf
->map
[(ucs4
& 0xff) >> 5];
294 *b
|= (1 << (ucs4
& 0x1f));
299 * An iterator for the leaves of a charset
302 typedef struct _fcCharSetIter
{
309 * Set iter->leaf to the leaf containing iter->ucs4 or higher
313 FcCharSetIterSet (const FcCharSet
*fcs
, FcCharSetIter
*iter
)
315 int pos
= FcCharSetFindLeafPos (fcs
, iter
->ucs4
);
326 iter
->ucs4
= (FcChar32
) FcCharSetGetNumbers(fcs
)[pos
] << 8;
328 iter
->leaf
= FcCharSetGetLeaf(fcs
, pos
);
331 printf ("set %08x: %08x\n", iter
->ucs4
, (FcChar32
) iter
->leaf
);
336 FcCharSetIterNext (const FcCharSet
*fcs
, FcCharSetIter
*iter
)
338 int pos
= iter
->pos
+ 1;
346 iter
->ucs4
= (FcChar32
) FcCharSetGetNumbers(fcs
)[pos
] << 8;
347 iter
->leaf
= FcCharSetGetLeaf(fcs
, pos
);
354 FcCharSetDump (const FcCharSet
*fcs
)
358 printf ("fcs %08x:\n", (FcChar32
) fcs
);
359 for (pos
= 0; pos
< fcs
->num
; pos
++)
361 FcCharLeaf
*leaf
= fcs
->leaves
[pos
];
362 FcChar32 ucs4
= (FcChar32
) fcs
->numbers
[pos
] << 8;
364 printf (" %08x: %08x\n", ucs4
, (FcChar32
) leaf
);
370 FcCharSetIterStart (const FcCharSet
*fcs
, FcCharSetIter
*iter
)
376 FcCharSetIterSet (fcs
, iter
);
380 FcCharSetCopy (FcCharSet
*src
)
382 if (src
->ref
!= FC_REF_CONSTANT
)
388 FcCharSetCopyPtr (FcCharSetPtr src
)
390 if (FcCharSetPtrU(src
)->ref
!= FC_REF_CONSTANT
)
391 FcCharSetPtrU(src
)->ref
++;
396 FcCharSetEqual (const FcCharSet
*a
, const FcCharSet
*b
)
398 FcCharSetIter ai
, bi
;
403 for (FcCharSetIterStart (a
, &ai
), FcCharSetIterStart (b
, &bi
);
405 FcCharSetIterNext (a
, &ai
), FcCharSetIterNext (b
, &bi
))
407 if (ai
.ucs4
!= bi
.ucs4
)
409 for (i
= 0; i
< 256/32; i
++)
410 if (ai
.leaf
->map
[i
] != bi
.leaf
->map
[i
])
413 return ai
.leaf
== bi
.leaf
;
417 FcCharSetAddLeaf (FcCharSet
*fcs
,
421 FcCharLeaf
*new = FcCharSetFindLeafCreate (fcs
, ucs4
);
429 FcCharSetOperate (const FcCharSet
*a
,
431 FcBool (*overlap
) (FcCharLeaf
*result
,
432 const FcCharLeaf
*al
,
433 const FcCharLeaf
*bl
),
438 FcCharSetIter ai
, bi
;
440 fcs
= FcCharSetCreate ();
443 FcCharSetIterStart (a
, &ai
);
444 FcCharSetIterStart (b
, &bi
);
445 while ((ai
.leaf
|| (bonly
&& bi
.leaf
)) && (bi
.leaf
|| (aonly
&& ai
.leaf
)))
447 if (ai
.ucs4
< bi
.ucs4
)
451 if (!FcCharSetAddLeaf (fcs
, ai
.ucs4
, ai
.leaf
))
453 FcCharSetIterNext (a
, &ai
);
458 FcCharSetIterSet (a
, &ai
);
461 else if (bi
.ucs4
< ai
.ucs4
)
465 if (!FcCharSetAddLeaf (fcs
, bi
.ucs4
, bi
.leaf
))
467 FcCharSetIterNext (b
, &bi
);
472 FcCharSetIterSet (b
, &bi
);
479 if ((*overlap
) (&leaf
, ai
.leaf
, bi
.leaf
))
481 if (!FcCharSetAddLeaf (fcs
, ai
.ucs4
, &leaf
))
484 FcCharSetIterNext (a
, &ai
);
485 FcCharSetIterNext (b
, &bi
);
490 FcCharSetDestroy (fcs
);
496 FcCharSetIntersectLeaf (FcCharLeaf
*result
,
497 const FcCharLeaf
*al
,
498 const FcCharLeaf
*bl
)
501 FcBool nonempty
= FcFalse
;
503 for (i
= 0; i
< 256/32; i
++)
504 if ((result
->map
[i
] = al
->map
[i
] & bl
->map
[i
]))
510 FcCharSetIntersect (const FcCharSet
*a
, const FcCharSet
*b
)
512 return FcCharSetOperate (a
, b
, FcCharSetIntersectLeaf
, FcFalse
, FcFalse
);
516 FcCharSetUnionLeaf (FcCharLeaf
*result
,
517 const FcCharLeaf
*al
,
518 const FcCharLeaf
*bl
)
522 for (i
= 0; i
< 256/32; i
++)
523 result
->map
[i
] = al
->map
[i
] | bl
->map
[i
];
528 FcCharSetUnion (const FcCharSet
*a
, const FcCharSet
*b
)
530 return FcCharSetOperate (a
, b
, FcCharSetUnionLeaf
, FcTrue
, FcTrue
);
534 FcCharSetSubtractLeaf (FcCharLeaf
*result
,
535 const FcCharLeaf
*al
,
536 const FcCharLeaf
*bl
)
539 FcBool nonempty
= FcFalse
;
541 for (i
= 0; i
< 256/32; i
++)
542 if ((result
->map
[i
] = al
->map
[i
] & ~bl
->map
[i
]))
548 FcCharSetSubtract (const FcCharSet
*a
, const FcCharSet
*b
)
550 return FcCharSetOperate (a
, b
, FcCharSetSubtractLeaf
, FcTrue
, FcFalse
);
554 FcCharSetHasChar (const FcCharSet
*fcs
, FcChar32 ucs4
)
556 FcCharLeaf
*leaf
= FcCharSetFindLeaf (fcs
, ucs4
);
559 return (leaf
->map
[(ucs4
& 0xff) >> 5] & (1 << (ucs4
& 0x1f))) != 0;
563 FcCharSetPopCount (FcChar32 c1
)
566 FcChar32 c2
= (c1
>> 1) & 033333333333;
567 c2
= c1
- c2
- ((c2
>> 1) & 033333333333);
568 return (((c2
+ (c2
>> 3)) & 030707070707) % 077);
572 FcCharSetIntersectCount (const FcCharSet
*a
, const FcCharSet
*b
)
574 FcCharSetIter ai
, bi
;
577 FcCharSetIterStart (a
, &ai
);
578 FcCharSetIterStart (b
, &bi
);
579 while (ai
.leaf
&& bi
.leaf
)
581 if (ai
.ucs4
== bi
.ucs4
)
583 FcChar32
*am
= ai
.leaf
->map
;
584 FcChar32
*bm
= bi
.leaf
->map
;
587 count
+= FcCharSetPopCount (*am
++ & *bm
++);
588 FcCharSetIterNext (a
, &ai
);
590 else if (ai
.ucs4
< bi
.ucs4
)
593 FcCharSetIterSet (a
, &ai
);
595 if (bi
.ucs4
< ai
.ucs4
)
598 FcCharSetIterSet (b
, &bi
);
605 FcCharSetCount (const FcCharSet
*a
)
610 for (FcCharSetIterStart (a
, &ai
); ai
.leaf
; FcCharSetIterNext (a
, &ai
))
613 FcChar32
*am
= ai
.leaf
->map
;
616 count
+= FcCharSetPopCount (*am
++);
622 FcCharSetSubtractCount (const FcCharSet
*a
, const FcCharSet
*b
)
624 FcCharSetIter ai
, bi
;
627 FcCharSetIterStart (a
, &ai
);
628 FcCharSetIterStart (b
, &bi
);
631 if (ai
.ucs4
<= bi
.ucs4
)
633 FcChar32
*am
= ai
.leaf
->map
;
635 if (ai
.ucs4
== bi
.ucs4
)
637 FcChar32
*bm
= bi
.leaf
->map
;;
639 count
+= FcCharSetPopCount (*am
++ & ~*bm
++);
644 count
+= FcCharSetPopCount (*am
++);
646 FcCharSetIterNext (a
, &ai
);
651 FcCharSetIterSet (b
, &bi
);
658 * return FcTrue iff a is a subset of b
661 FcCharSetIsSubset (const FcCharSet
*a
, const FcCharSet
*b
)
666 if (a
== b
) return FcTrue
;
669 while (ai
< a
->num
&& bi
< b
->num
)
671 an
= FcCharSetGetNumbers(a
)[ai
];
672 bn
= FcCharSetGetNumbers(b
)[bi
];
674 * Check matching pages
678 FcChar32
*am
= FcCharSetGetLeaf(a
, ai
)->map
;
679 FcChar32
*bm
= FcCharSetGetLeaf(b
, bi
)->map
;
685 * Does am have any bits not in bm?
695 * Does a have any pages not in b?
702 int high
= b
->num
- 1;
705 * Search for page 'an' in 'b'
709 int mid
= (low
+ high
) >> 1;
710 bn
= FcCharSetGetNumbers(b
)[mid
];
722 while (bi
< b
->num
&& FcCharSetGetNumbers(b
)[bi
] < an
)
727 * did we look at every page?
733 * These two functions efficiently walk the entire charmap for
734 * other software (like pango) that want their own copy
738 FcCharSetNextPage (const FcCharSet
*a
,
739 FcChar32 map
[FC_CHARSET_MAP_SIZE
],
746 FcCharSetIterSet (a
, &ai
);
748 return FC_CHARSET_DONE
;
751 * Save current information
754 memcpy (map
, ai
.leaf
->map
, sizeof (ai
.leaf
->map
));
758 FcCharSetIterNext (a
, &ai
);
765 FcCharSetFirstPage (const FcCharSet
*a
,
766 FcChar32 map
[FC_CHARSET_MAP_SIZE
],
770 return FcCharSetNextPage (a
, map
, next
);
774 * old coverage API, rather hard to use correctly
777 FcCharSetCoverage (const FcCharSet
*a
, FcChar32 page
, FcChar32
*result
);
780 FcCharSetCoverage (const FcCharSet
*a
, FcChar32 page
, FcChar32
*result
)
785 FcCharSetIterSet (a
, &ai
);
788 memset (result
, '\0', 256 / 8);
793 memcpy (result
, ai
.leaf
->map
, sizeof (ai
.leaf
->map
));
794 FcCharSetIterNext (a
, &ai
);
801 * ASCII representation of charsets.
803 * Each leaf is represented as 9 32-bit values, the code of the first character followed
804 * by 8 32 bit values for the leaf itself. Each value is encoded as 5 ASCII characters,
805 * only 85 different values are used to avoid control characters as well as the other
806 * characters used to encode font names. 85**5 > 2^32 so things work out, but
807 * it's not exactly human readable output. As a special case, 0 is encoded as a space
810 static const unsigned char charToValue
[256] = {
811 /* "" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
812 /* "\b" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
813 /* "\020" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
814 /* "\030" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
815 /* " " */ 0xff, 0x00, 0xff, 0x01, 0x02, 0x03, 0x04, 0xff,
816 /* "(" */ 0x05, 0x06, 0x07, 0x08, 0xff, 0xff, 0x09, 0x0a,
817 /* "0" */ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
818 /* "8" */ 0x13, 0x14, 0xff, 0x15, 0x16, 0xff, 0x17, 0x18,
819 /* "@" */ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
820 /* "H" */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
821 /* "P" */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
822 /* "X" */ 0x31, 0x32, 0x33, 0x34, 0xff, 0x35, 0x36, 0xff,
823 /* "`" */ 0xff, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
824 /* "h" */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
825 /* "p" */ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
826 /* "x" */ 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0xff,
827 /* "\200" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
828 /* "\210" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
829 /* "\220" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
830 /* "\230" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
831 /* "\240" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
832 /* "\250" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
833 /* "\260" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
834 /* "\270" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
835 /* "\300" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
836 /* "\310" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
837 /* "\320" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
838 /* "\330" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
839 /* "\340" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
840 /* "\350" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
841 /* "\360" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
842 /* "\370" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
845 static const FcChar8 valueToChar
[0x55] = {
846 /* 0x00 */ '!', '#', '$', '%', '&', '(', ')', '*',
847 /* 0x08 */ '+', '.', '/', '0', '1', '2', '3', '4',
848 /* 0x10 */ '5', '6', '7', '8', '9', ';', '<', '>',
849 /* 0x18 */ '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
850 /* 0x20 */ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
851 /* 0x28 */ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
852 /* 0x30 */ 'W', 'X', 'Y', 'Z', '[', ']', '^', 'a',
853 /* 0x38 */ 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
854 /* 0x40 */ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
855 /* 0x48 */ 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
856 /* 0x50 */ 'z', '{', '|', '}', '~',
860 FcCharSetParseValue (FcChar8
*string
, FcChar32
*value
)
874 for (i
= 0; i
< 5; i
++)
876 if (!(c
= (FcChar32
) (unsigned char) *string
++))
889 FcCharSetUnparseValue (FcStrBuf
*buf
, FcChar32 value
)
894 return FcStrBufChar (buf
, ' ');
899 FcChar8
*s
= string
+ 5;
901 for (i
= 0; i
< 5; i
++)
903 *--s
= valueToChar
[value
% 85];
906 for (i
= 0; i
< 5; i
++)
907 if (!FcStrBufChar (buf
, *s
++))
913 typedef struct _FcCharLeafEnt FcCharLeafEnt
;
915 struct _FcCharLeafEnt
{
921 #define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt))
922 static FcCharLeafEnt
**FcCharLeafBlocks
;
923 static int FcCharLeafBlockCount
;
925 static FcCharLeafEnt
*
926 FcCharLeafEntCreate (void)
928 static FcCharLeafEnt
*block
;
933 FcCharLeafEnt
**newBlocks
;
935 FcCharLeafBlockCount
++;
936 newBlocks
= realloc (FcCharLeafBlocks
, FcCharLeafBlockCount
* sizeof (FcCharLeafEnt
*));
939 FcCharLeafBlocks
= newBlocks
;
940 block
= FcCharLeafBlocks
[FcCharLeafBlockCount
-1] = malloc (FC_CHAR_LEAF_BLOCK
* sizeof (FcCharLeafEnt
));
943 FcMemAlloc (FC_MEM_CHARLEAF
, FC_CHAR_LEAF_BLOCK
* sizeof (FcCharLeafEnt
));
944 remain
= FC_CHAR_LEAF_BLOCK
;
950 #define FC_CHAR_LEAF_HASH_SIZE 257
953 FcCharLeafHash (FcCharLeaf
*leaf
)
958 for (i
= 0; i
< 256/32; i
++)
959 hash
= ((hash
<< 1) | (hash
>> 31)) ^ leaf
->map
[i
];
963 static int FcCharLeafTotal
;
964 static int FcCharLeafUsed
;
966 static FcCharLeafEnt
*FcCharLeafHashTable
[FC_CHAR_LEAF_HASH_SIZE
];
969 FcCharSetFreezeLeaf (FcCharLeaf
*leaf
)
971 FcChar32 hash
= FcCharLeafHash (leaf
);
972 FcCharLeafEnt
**bucket
= &FcCharLeafHashTable
[hash
% FC_CHAR_LEAF_HASH_SIZE
];
976 for (ent
= *bucket
; ent
; ent
= ent
->next
)
978 if (ent
->hash
== hash
&& !memcmp (&ent
->leaf
, leaf
, sizeof (FcCharLeaf
)))
982 ent
= FcCharLeafEntCreate();
994 FcCharSetThawAllLeaf (void)
998 for (i
= 0; i
< FC_CHAR_LEAF_HASH_SIZE
; i
++)
999 FcCharLeafHashTable
[i
] = 0;
1001 FcCharLeafTotal
= 0;
1004 for (i
= 0; i
< FcCharLeafBlockCount
; i
++)
1005 free (FcCharLeafBlocks
[i
]);
1007 free (FcCharLeafBlocks
);
1008 FcCharLeafBlocks
= 0;
1009 FcCharLeafBlockCount
= 0;
1012 typedef struct _FcCharSetEnt FcCharSetEnt
;
1014 struct _FcCharSetEnt
{
1020 #define FC_CHAR_SET_HASH_SIZE 67
1023 FcCharSetHash (FcCharSet
*fcs
)
1028 /* hash in leaves */
1029 for (i
= 0; i
< fcs
->num
* sizeof (FcCharLeaf
*) / sizeof (FcChar32
); i
++)
1030 hash
= ((hash
<< 1) | (hash
>> 31)) ^ (FcChar32
)(FcCharSetGetLeaf(fcs
, i
)->map
);
1031 /* hash in numbers */
1032 for (i
= 0; i
< fcs
->num
; i
++)
1033 hash
= ((hash
<< 1) | (hash
>> 31)) ^ *FcCharSetGetNumbers(fcs
);
1037 static int FcCharSetTotal
;
1038 static int FcCharSetUsed
;
1039 static int FcCharSetTotalEnts
, FcCharSetUsedEnts
;
1041 static FcCharSetEnt
*FcCharSetHashTable
[FC_CHAR_SET_HASH_SIZE
];
1044 FcCharSetFreezeBase (FcCharSet
*fcs
)
1046 FcChar32 hash
= FcCharSetHash (fcs
);
1047 FcCharSetEnt
**bucket
= &FcCharSetHashTable
[hash
% FC_CHAR_SET_HASH_SIZE
];
1052 FcCharSetTotalEnts
+= fcs
->num
;
1053 for (ent
= *bucket
; ent
; ent
= ent
->next
)
1055 if (ent
->hash
== hash
&&
1056 ent
->set
.num
== fcs
->num
&&
1057 !memcmp (FcCharSetGetNumbers(&ent
->set
),
1058 FcCharSetGetNumbers(fcs
),
1059 fcs
->num
* sizeof (FcChar16
)))
1064 for (i
= 0; i
< fcs
->num
; i
++)
1065 if (FcCharSetGetLeaf(&ent
->set
, i
) != FcCharSetGetLeaf(fcs
, i
))
1072 size
= (sizeof (FcCharSetEnt
) +
1073 fcs
->num
* sizeof (FcCharLeaf
*) +
1074 fcs
->num
* sizeof (FcChar16
));
1075 ent
= malloc (size
);
1078 FcMemAlloc (FC_MEM_CHARSET
, size
);
1080 FcCharSetUsedEnts
+= fcs
->num
;
1082 ent
->set
.ref
= FC_REF_CONSTANT
;
1083 ent
->set
.num
= fcs
->num
;
1084 ent
->set
.storage
= fcs
->storage
;
1085 if (fcs
->storage
== FcStorageDynamic
)
1089 ent
->set
.u
.dyn
.leaves
= (FcCharLeaf
**) (ent
+ 1);
1090 ent
->set
.u
.dyn
.numbers
= (FcChar16
*) (ent
->set
.u
.dyn
.leaves
+ fcs
->num
);
1091 memcpy (ent
->set
.u
.dyn
.leaves
, fcs
->u
.dyn
.leaves
, fcs
->num
* sizeof (FcCharLeaf
*));
1092 memcpy (ent
->set
.u
.dyn
.numbers
, fcs
->u
.dyn
.numbers
, fcs
->num
* sizeof (FcChar16
));
1096 ent
->set
.u
.dyn
.leaves
= 0;
1097 ent
->set
.u
.dyn
.numbers
= 0;
1102 ent
->set
.u
.stat
.leafidx_offset
= fcs
->u
.stat
.leafidx_offset
;
1103 ent
->set
.u
.stat
.numbers_offset
= fcs
->u
.stat
.numbers_offset
;
1107 ent
->next
= *bucket
;
1113 FcCharSetThawAll (void)
1116 FcCharSetEnt
*ent
, *next
;
1118 for (i
= 0; i
< FC_CHAR_SET_HASH_SIZE
; i
++)
1120 for (ent
= FcCharSetHashTable
[i
]; ent
; ent
= next
)
1125 FcCharSetHashTable
[i
] = 0;
1129 FcCharSetTotalEnts
= 0;
1131 FcCharSetUsedEnts
= 0;
1133 FcCharSetThawAllLeaf ();
1137 FcCharSetFreeze (FcCharSet
*fcs
)
1144 b
= FcCharSetCreate ();
1147 for (i
= 0; i
< fcs
->num
; i
++)
1149 l
= FcCharSetFreezeLeaf (FcCharSetGetLeaf(fcs
, i
));
1152 if (!FcCharSetInsertLeaf (b
, FcCharSetGetNumbers(fcs
)[i
] << 8, l
))
1155 n
= FcCharSetFreezeBase (b
);
1157 if (b
->storage
== FcStorageDynamic
)
1159 if (b
->u
.dyn
.leaves
)
1161 FcMemFree (FC_MEM_CHARSET
, b
->num
* sizeof (FcCharLeaf
*));
1162 free (b
->u
.dyn
.leaves
);
1164 if (b
->u
.dyn
.numbers
)
1166 FcMemFree (FC_MEM_CHARSET
, b
->num
* sizeof (FcChar16
));
1167 free (b
->u
.dyn
.numbers
);
1170 FcMemFree (FC_MEM_CHARSET
, sizeof (FcCharSet
));
1177 FcNameParseCharSet (FcChar8
*string
)
1179 FcCharSet
*c
, *n
= 0;
1186 c
= FcCharSetCreate ();
1191 string
= FcCharSetParseValue (string
, &ucs4
);
1195 for (i
= 0; i
< 256/32; i
++)
1197 string
= FcCharSetParseValue (string
, &temp
.map
[i
]);
1200 bits
|= temp
.map
[i
];
1204 leaf
= FcCharSetFreezeLeaf (&temp
);
1207 if (!FcCharSetInsertLeaf (c
, ucs4
, leaf
))
1212 printf (" %8s %8s %8s %8s\n", "total", "totalmem", "new", "newmem");
1213 printf ("Leaves: %8d %8d %8d %8d\n",
1214 FcCharLeafTotal
, sizeof (FcCharLeaf
) * FcCharLeafTotal
,
1215 FcCharLeafUsed
, sizeof (FcCharLeaf
) * FcCharLeafUsed
);
1216 printf ("Charsets: %8d %8d %8d %8d\n",
1217 FcCharSetTotal
, sizeof (FcCharSet
) * FcCharSetTotal
,
1218 FcCharSetUsed
, sizeof (FcCharSet
) * FcCharSetUsed
);
1219 printf ("Tables: %8d %8d %8d %8d\n",
1220 FcCharSetTotalEnts
, FcCharSetTotalEnts
* (sizeof (FcCharLeaf
*) + sizeof (FcChar16
)),
1221 FcCharSetUsedEnts
, FcCharSetUsedEnts
* (sizeof (FcCharLeaf
*) + sizeof (FcChar16
)));
1222 printf ("Total: %8s %8d %8s %8d\n",
1224 sizeof (FcCharLeaf
) * FcCharLeafTotal
+
1225 sizeof (FcCharSet
) * FcCharSetTotal
+
1226 FcCharSetTotalEnts
* (sizeof (FcCharLeaf
*) + sizeof (FcChar16
)),
1228 sizeof (FcCharLeaf
) * FcCharLeafUsed
+
1229 sizeof (FcCharSet
) * FcCharSetUsed
+
1230 FcCharSetUsedEnts
* (sizeof (FcCharLeaf
*) + sizeof (FcChar16
)));
1232 n
= FcCharSetFreezeBase (c
);
1234 if (c
->storage
== FcStorageDynamic
)
1236 if (c
->u
.dyn
.leaves
)
1238 FcMemFree (FC_MEM_CHARSET
, c
->num
* sizeof (FcCharLeaf
*));
1239 free (c
->u
.dyn
.leaves
);
1241 if (c
->u
.dyn
.numbers
)
1243 FcMemFree (FC_MEM_CHARSET
, c
->num
* sizeof (FcChar16
));
1244 free (c
->u
.dyn
.numbers
);
1246 FcMemFree (FC_MEM_CHARSET
, sizeof (FcCharSet
));
1254 FcNameUnparseCharSet (FcStrBuf
*buf
, const FcCharSet
*c
)
1262 for (FcCharSetIterStart (c
, &ci
);
1264 FcCharSetIterNext (c
, &ci
))
1266 if (!FcCharSetUnparseValue (buf
, ci
.ucs4
))
1268 for (i
= 0; i
< 256/32; i
++)
1269 if (!FcCharSetUnparseValue (buf
, ci
.leaf
->map
[i
]))
1276 FcCharSetIter ci
, checki
;
1278 /* null terminate for parser */
1279 FcStrBufChar (buf
, '\0');
1280 /* step back over null for life after test */
1282 check
= FcNameParseCharSet (buf
->buf
+ len
);
1283 FcCharSetIterStart (c
, &ci
);
1284 FcCharSetIterStart (check
, &checki
);
1285 while (ci
.leaf
|| checki
.leaf
)
1287 if (ci
.ucs4
< checki
.ucs4
)
1289 printf ("Missing leaf node at 0x%x\n", ci
.ucs4
);
1290 FcCharSetIterNext (c
, &ci
);
1292 else if (checki
.ucs4
< ci
.ucs4
)
1294 printf ("Extra leaf node at 0x%x\n", checki
.ucs4
);
1295 FcCharSetIterNext (check
, &checki
);
1300 FcChar32
*cm
= ci
.leaf
->map
;
1301 FcChar32
*checkm
= checki
.leaf
->map
;
1303 for (i
= 0; i
< 256; i
+= 32)
1306 printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
1307 ci
.ucs4
+ i
, *cm
, *checkm
);
1311 FcCharSetIterNext (c
, &ci
);
1312 FcCharSetIterNext (check
, &checki
);
1315 if ((missing
= FcCharSetSubtractCount (c
, check
)))
1316 printf ("%d missing in reparsed result\n", missing
);
1317 if ((missing
= FcCharSetSubtractCount (check
, c
)))
1318 printf ("%d extra in reparsed result\n", missing
);
1319 FcCharSetDestroy (check
);
1328 FcCharSetPtrU (FcCharSetPtr ci
)
1332 case FcStorageDynamic
:
1334 case FcStorageStatic
:
1335 return &charsets
[ci
.u
.stat
];
1342 FcCharSetPtrCreateDynamic(FcCharSet
*c
)
1346 new.storage
= FcStorageDynamic
;
1352 FcCharSetPrepareSerialize(FcCharSet
*c
)
1354 /* note the redundancy */
1356 charset_leaf_idx_count
++;
1357 charset_leaf_count
+= c
->num
;
1358 charset_numbers_count
+= c
->num
;
1363 FcCharSetSerialize(FcCharSet
*c
)
1371 charsets
= malloc(sizeof(FcCharSet
) * charset_count
);
1372 if (!charsets
) goto bail
;
1373 numbers
= malloc(sizeof(FcChar16
) * charset_numbers_count
);
1374 if (!numbers
) goto bail1
;
1375 leaves
= malloc(sizeof(FcCharLeaf
) * charset_leaf_count
);
1376 if (!leaves
) goto bail2
;
1377 leaf_idx
= malloc(sizeof(int)*charset_leaf_idx_count
);
1378 if (!leaf_idx
) goto bail3
;
1381 new.ref
= FC_REF_CONSTANT
;
1382 new.storage
= FcStorageStatic
;
1383 new.u
.stat
.leafidx_offset
= charset_leaf_idx_ptr
;
1384 new.u
.stat
.numbers_offset
= charset_numbers_ptr
;
1387 newp
.storage
= FcStorageStatic
;
1388 newp
.u
.stat
= charset_ptr
;
1389 charsets
[charset_ptr
++] = new;
1391 leaf_idx
[charset_leaf_idx_ptr
++] = charset_leaf_ptr
;
1392 for (i
= 0; i
< c
->num
; i
++)
1394 memcpy (&leaves
[charset_leaf_ptr
++],
1395 c
->u
.dyn
.leaves
[i
], sizeof(FcCharLeaf
));
1396 numbers
[charset_numbers_ptr
++] = c
->u
.dyn
.numbers
[i
];
1408 return FcCharSetPtrCreateDynamic(0);
1412 FcCharSetRead (int fd
, FcCache metadata
)
1414 charsets
= mmap(NULL
,
1415 metadata
.charsets_length
* sizeof (FcCharSet
),
1417 MAP_SHARED
, fd
, metadata
.charsets_offset
);
1418 if (charsets
== MAP_FAILED
)
1420 charset_count
= charset_ptr
= metadata
.charsets_length
;
1423 metadata
.charset_num_sum
* sizeof (FcCharLeaf
),
1425 MAP_SHARED
, fd
, metadata
.charset_leaf_offset
);
1426 if (leaves
== MAP_FAILED
)
1428 charset_leaf_count
= charset_leaf_ptr
= metadata
.charset_num_sum
;
1430 leaf_idx
= mmap(NULL
,
1431 metadata
.charsets_length
* sizeof (FcCharLeaf
*),
1433 MAP_SHARED
, fd
, metadata
.charset_leafidx_offset
);
1434 if (leaf_idx
== MAP_FAILED
)
1436 charset_leaf_idx_count
= charset_leaf_idx_ptr
= metadata
.charsets_length
;
1438 numbers
= mmap(NULL
,
1439 metadata
.charset_num_sum
* sizeof (FcChar16
),
1441 MAP_SHARED
, fd
, metadata
.charset_numbers_offset
);
1442 if (numbers
== MAP_FAILED
)
1444 charset_numbers_count
= charset_numbers_ptr
= metadata
.charset_num_sum
;
1449 munmap (leaf_idx
, metadata
.charsets_length
* sizeof (FcCharLeaf
*));
1451 munmap (leaves
, metadata
.charset_num_sum
* sizeof (FcCharLeaf
));
1453 munmap (charsets
, metadata
.charsets_length
* sizeof (FcCharSet
));
1459 FcCharSetWrite (int fd
, FcCache
*metadata
)
1461 metadata
->charsets_length
= charset_ptr
;
1462 metadata
->charsets_offset
= FcCacheNextOffset(fd
);
1464 if (charset_ptr
> 0)
1466 lseek (fd
, metadata
->charsets_offset
, SEEK_SET
);
1467 if (write (fd
, charsets
, charset_ptr
* sizeof(FcCharSet
)) == -1)
1471 metadata
->charset_leaf_offset
= FcCacheNextOffset(fd
);
1472 metadata
->charset_num_sum
= charset_leaf_ptr
;
1473 if (charset_leaf_ptr
> 0)
1475 lseek (fd
, metadata
->charset_leaf_offset
, SEEK_SET
);
1476 if (write (fd
, leaves
, charset_leaf_ptr
* sizeof(FcCharLeaf
)) == -1)
1480 metadata
->charset_leafidx_offset
= FcCacheNextOffset(fd
);
1481 if (charset_leaf_idx_ptr
> 0)
1483 lseek (fd
, metadata
->charset_leafidx_offset
, SEEK_SET
);
1484 if (write (fd
, leaf_idx
, charset_leaf_idx_ptr
* sizeof(FcCharLeaf
*)) == -1)
1489 metadata
->charset_numbers_offset
= FcCacheNextOffset(fd
);
1490 if (charset_leaf_ptr
> 0)
1492 lseek (fd
, metadata
->charset_numbers_offset
, SEEK_SET
);
1493 if (write (fd
, numbers
, charset_leaf_ptr
* sizeof(FcChar16
)) == -1)
1501 FcCharSetGetLeaf(const FcCharSet
*c
, int i
)
1505 case FcStorageDynamic
:
1506 return c
->u
.dyn
.leaves
[i
];
1507 case FcStorageStatic
:
1508 return &leaves
[leaf_idx
[c
->u
.stat
.leafidx_offset
]+i
];
1515 FcCharSetGetNumbers(const FcCharSet
*c
)
1519 case FcStorageDynamic
:
1520 return c
->u
.dyn
.numbers
;
1521 case FcStorageStatic
:
1522 return &numbers
[c
->u
.stat
.numbers_offset
];