]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
bf34c2e2c4c1869f6c12303792a4f065e60e17e1
[fontconfig.git] / src / fcpat.c
1 /*
2  * Copyright © 2000 Keith Packard
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of Keith Packard not be used in
9  * advertising or publicity pertaining to distribution of the software without
10  * specific, written prior permission.  Keith Packard makes no
11  * representations about the suitability of this software for any purpose.  It
12  * is provided "as is" without express or implied warranty.
13  *
14  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include "fcint.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 static FcBool
29 FcStrHashed (const FcChar8 *name);
30
31 FcPattern *
32 FcPatternCreate (void)
33 {
34     FcPattern   *p;
35
36     p = (FcPattern *) malloc (sizeof (FcPattern));
37     if (!p)
38         return 0;
39     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
40     p->num = 0;
41     p->size = 0;
42     p->elts_offset = FcPtrToOffset (p, NULL);
43     p->ref = 1;
44     return p;
45 }
46
47 void
48 FcValueDestroy (FcValue v)
49 {
50     switch (v.type) {
51     case FcTypeString:
52         if (!FcStrHashed (v.u.s))
53             FcStrFree ((FcChar8 *) v.u.s);
54         break;
55     case FcTypeMatrix:
56         FcMatrixFree ((FcMatrix *) v.u.m);
57         break;
58     case FcTypeCharSet:
59         FcCharSetDestroy ((FcCharSet *) v.u.c);
60         break;
61     case FcTypeLangSet:
62         FcLangSetDestroy ((FcLangSet *) v.u.l);
63         break;
64     default:
65         break;
66     }
67 }
68
69 FcValue
70 FcValueCanonicalize (const FcValue *v)
71 {
72     FcValue new;
73
74     switch (v->type)
75     {
76     case FcTypeString:
77         new.u.s = fc_value_string(v);
78         new.type = FcTypeString;
79         break;
80     case FcTypeCharSet:
81         new.u.c = fc_value_charset(v);
82         new.type = FcTypeCharSet;
83         break;
84     case FcTypeLangSet:
85         new.u.l = fc_value_langset(v);
86         new.type = FcTypeLangSet;
87         break;
88     default:
89         new = *v;
90         break;
91     }
92     return new;
93 }
94
95 FcValue
96 FcValueSave (FcValue v)
97 {
98     switch (v.type) {
99     case FcTypeString:
100         v.u.s = FcStrCopy (v.u.s);
101         if (!v.u.s)
102             v.type = FcTypeVoid;
103         break;
104     case FcTypeMatrix:
105         v.u.m = FcMatrixCopy (v.u.m);
106         if (!v.u.m)
107             v.type = FcTypeVoid;
108         break;
109     case FcTypeCharSet:
110         v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
111         if (!v.u.c)
112             v.type = FcTypeVoid;
113         break;
114     case FcTypeLangSet:
115         v.u.l = FcLangSetCopy (v.u.l);
116         if (!v.u.l)
117             v.type = FcTypeVoid;
118         break;
119     default:
120         break;
121     }
122     return v;
123 }
124
125 void
126 FcValueListDestroy (FcValueListPtr l)
127 {
128     FcValueListPtr next;
129     for (; l; l = next)
130     {
131         switch (l->value.type) {
132         case FcTypeString:
133             if (!FcStrHashed ((FcChar8 *)l->value.u.s))
134                 FcStrFree ((FcChar8 *)l->value.u.s);
135             break;
136         case FcTypeMatrix:
137             FcMatrixFree ((FcMatrix *)l->value.u.m);
138             break;
139         case FcTypeCharSet:
140             FcCharSetDestroy 
141                 ((FcCharSet *) (l->value.u.c));
142             break;
143         case FcTypeLangSet:
144             FcLangSetDestroy 
145                 ((FcLangSet *) (l->value.u.l));
146             break;
147         default:
148             break;
149         }
150         next = FcValueListNext(l);
151         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
152         free(l);
153     }
154 }
155
156 FcBool
157 FcValueEqual (FcValue va, FcValue vb)
158 {
159     if (va.type != vb.type)
160     {
161         if (va.type == FcTypeInteger)
162         {
163             va.type = FcTypeDouble;
164             va.u.d = va.u.i;
165         }
166         if (vb.type == FcTypeInteger)
167         {
168             vb.type = FcTypeDouble;
169             vb.u.d = vb.u.i;
170         }
171         if (va.type != vb.type)
172             return FcFalse;
173     }
174     switch (va.type) {
175     case FcTypeVoid:
176         return FcTrue;
177     case FcTypeInteger:
178         return va.u.i == vb.u.i;
179     case FcTypeDouble:
180         return va.u.d == vb.u.d;
181     case FcTypeString:
182         return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
183     case FcTypeBool:
184         return va.u.b == vb.u.b;
185     case FcTypeMatrix:
186         return FcMatrixEqual (va.u.m, vb.u.m);
187     case FcTypeCharSet:
188         return FcCharSetEqual (va.u.c, vb.u.c);
189     case FcTypeFTFace:
190         return va.u.f == vb.u.f;
191     case FcTypeLangSet:
192         return FcLangSetEqual (va.u.l, vb.u.l);
193     }
194     return FcFalse;
195 }
196
197 static FcChar32
198 FcDoubleHash (double d)
199 {
200     if (d < 0)
201         d = -d;
202     if (d > 0xffffffff)
203         d = 0xffffffff;
204     return (FcChar32) d;
205 }
206
207 FcChar32
208 FcStringHash (const FcChar8 *s)
209 {
210     FcChar8     c;
211     FcChar32    h = 0;
212     
213     if (s)
214         while ((c = *s++))
215             h = ((h << 1) | (h >> 31)) ^ c;
216     return h;
217 }
218
219 static FcChar32
220 FcValueHash (const FcValue *v)
221 {
222     switch (fc_storage_type(v)) {
223     case FcTypeVoid:
224         return 0;
225     case FcTypeInteger:
226         return (FcChar32) v->u.i;
227     case FcTypeDouble:
228         return FcDoubleHash (v->u.d);
229     case FcTypeString:
230         return FcStringHash (fc_value_string(v));
231     case FcTypeBool:
232         return (FcChar32) v->u.b;
233     case FcTypeMatrix:
234         return (FcDoubleHash (v->u.m->xx) ^ 
235                 FcDoubleHash (v->u.m->xy) ^ 
236                 FcDoubleHash (v->u.m->yx) ^ 
237                 FcDoubleHash (v->u.m->yy));
238     case FcTypeCharSet:
239         return (FcChar32) fc_value_charset(v)->num;
240     case FcTypeFTFace:
241         return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
242                FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
243     case FcTypeLangSet:
244         return FcLangSetHash (fc_value_langset(v));
245     }
246     return FcFalse;
247 }
248
249 static FcBool
250 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
251 {
252     if (la == lb)
253         return FcTrue;
254
255     while (la && lb)
256     {
257         if (!FcValueEqual (la->value, lb->value))
258             return FcFalse;
259         la = FcValueListNext(la);
260         lb = FcValueListNext(lb);
261     }
262     if (la || lb)
263         return FcFalse;
264     return FcTrue;
265 }
266
267 static FcChar32
268 FcValueListHash (FcValueListPtr l)
269 {
270     FcChar32    hash = 0;
271     
272     for (; l; l = FcValueListNext(l))
273     {
274         hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value);
275     }
276     return hash;
277 }
278
279 void
280 FcPatternDestroy (FcPattern *p)
281 {
282     int             i;
283     FcPatternElt    *elts;
284     
285     if (p->ref == FC_REF_CONSTANT)
286     {
287         FcCacheObjectDereference (p);
288         return;
289     }
290         
291     if (--p->ref > 0)
292         return;
293
294     elts = FcPatternElts (p);
295     for (i = 0; i < p->num; i++)
296         FcValueListDestroy (FcPatternEltValues(&elts[i]));
297
298     FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
299     free (elts);
300     FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
301     free (p);
302 }
303
304 static int
305 FcPatternObjectPosition (const FcPattern *p, FcObject object)
306 {
307     int     low, high, mid, c;
308     FcPatternElt    *elts = FcPatternElts(p);
309
310     low = 0;
311     high = p->num - 1;
312     c = 1;
313     mid = 0;
314     while (low <= high)
315     {
316         mid = (low + high) >> 1;
317         c = elts[mid].object - object;
318         if (c == 0)
319             return mid;
320         if (c < 0)
321             low = mid + 1;
322         else
323             high = mid - 1;
324     }
325     if (c < 0)
326         mid++;
327     return -(mid + 1);
328 }
329
330 FcPatternElt *
331 FcPatternObjectFindElt (const FcPattern *p, FcObject object)
332 {
333     int     i = FcPatternObjectPosition (p, object);
334     if (i < 0)
335         return 0;
336     return &FcPatternElts(p)[i];
337 }
338
339 FcPatternElt *
340 FcPatternObjectInsertElt (FcPattern *p, FcObject object)
341 {
342     int             i;
343     FcPatternElt   *e;
344     
345     i = FcPatternObjectPosition (p, object);
346     if (i < 0)
347     {
348         i = -i - 1;
349     
350         /* reallocate array */
351         if (p->num + 1 >= p->size)
352         {
353             int s = p->size + 16;
354             if (p->size)
355             {
356                 FcPatternElt *e0 = FcPatternElts(p);
357                 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
358                 if (!e) /* maybe it was mmapped */
359                 {
360                     e = malloc(s * sizeof (FcPatternElt));
361                     if (e)
362                         memcpy(e, e0, p->num * sizeof (FcPatternElt));
363                 }
364             }
365             else
366                 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
367             if (!e)
368                 return FcFalse;
369             p->elts_offset = FcPtrToOffset (p, e);
370             if (p->size)
371                 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
372             FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
373             while (p->size < s)
374             {
375                 e[p->size].object = 0;
376                 e[p->size].values = NULL;
377                 p->size++;
378             }
379         }
380         
381         e = FcPatternElts(p);
382         /* move elts up */
383         memmove (e + i + 1,
384                  e + i,
385                  sizeof (FcPatternElt) *
386                  (p->num - i));
387                  
388         /* bump count */
389         p->num++;
390         
391         e[i].object = object;
392         e[i].values = NULL;
393     }
394     
395     return FcPatternElts(p) + i;
396 }
397
398 FcBool
399 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
400 {
401     int i;
402     FcPatternElt   *pae, *pbe;
403
404     if (pa == pb)
405         return FcTrue;
406
407     if (pa->num != pb->num)
408         return FcFalse;
409     pae = FcPatternElts(pa);
410     pbe = FcPatternElts(pb);
411     for (i = 0; i < pa->num; i++)
412     {
413         if (pae[i].object != pbe[i].object)
414             return FcFalse;
415         if (!FcValueListEqual (FcPatternEltValues(&pae[i]),
416                                FcPatternEltValues(&pbe[i])))
417             return FcFalse;
418     }
419     return FcTrue;
420 }
421
422 FcChar32
423 FcPatternHash (const FcPattern *p)
424 {
425     int         i;
426     FcChar32    h = 0;
427     FcPatternElt    *pe = FcPatternElts(p);
428
429     for (i = 0; i < p->num; i++)
430     {
431         h = (((h << 1) | (h >> 31)) ^ 
432              pe[i].object ^
433              FcValueListHash (FcPatternEltValues(&pe[i])));
434     }
435     return h;
436 }
437
438 FcBool
439 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
440 {
441     FcPatternElt    *ea, *eb;
442     int             i;
443     
444     for (i = 0; i < os->nobject; i++)
445     {
446         FcObject    object = FcObjectFromName (os->objects[i]);
447         ea = FcPatternObjectFindElt (pai, object);
448         eb = FcPatternObjectFindElt (pbi, object);
449         if (ea)
450         {
451             if (!eb)
452                 return FcFalse;
453             if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
454                 return FcFalse;
455         }
456         else
457         {
458             if (eb)
459                 return FcFalse;
460         }
461     }
462     return FcTrue;
463 }
464
465 FcBool
466 FcPatternObjectAddWithBinding  (FcPattern       *p,
467                                 FcObject        object,
468                                 FcValue         value,
469                                 FcValueBinding  binding,
470                                 FcBool          append)
471 {
472     FcPatternElt   *e;
473     FcValueListPtr new, *prev;
474
475     if (p->ref == FC_REF_CONSTANT)
476         goto bail0;
477
478     new = malloc (sizeof (FcValueList));
479     if (!new)
480         goto bail0;
481
482     memset(new, 0, sizeof (FcValueList));
483     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
484     /* dup string */
485     if (value.type == FcTypeString)
486     {
487         value.u.s = FcStrStaticName (value.u.s);
488         if (!value.u.s)
489             value.type = FcTypeVoid;
490     }
491     else
492         value = FcValueSave (value);
493     if (value.type == FcTypeVoid)
494         goto bail1;
495
496     /*
497      * Make sure the stored type is valid for built-in objects
498      */
499     if (!FcObjectValidType (object, value.type))
500     {
501         if (FcDebug() & FC_DBG_OBJTYPES)
502         {
503             printf ("FcPattern object %s does not accept value ",
504                     FcObjectName (object));
505             FcValuePrint (value);
506         }
507         goto bail1;
508     }
509
510     new->value = value;
511     new->binding = binding;
512     new->next = NULL;
513     
514     e = FcPatternObjectInsertElt (p, object);
515     if (!e)
516         goto bail2;
517     
518     if (append)
519     {
520         for (prev = &e->values; *prev; prev = &(*prev)->next)
521             ;
522         *prev = new;
523     }
524     else
525     {
526         new->next = e->values;
527         e->values = new;
528     }
529     
530     return FcTrue;
531
532 bail2:    
533     FcValueDestroy (value);
534 bail1:
535     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
536     free (new);
537 bail0:
538     return FcFalse;
539 }
540
541 FcBool
542 FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
543 {
544     return FcPatternObjectAddWithBinding (p, object,
545                                           value, FcValueBindingStrong, append);
546 }
547
548 FcBool
549 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
550 {
551     return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
552                                           value, FcValueBindingStrong, append);
553 }
554
555 FcBool
556 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
557 {
558     return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
559                                           value, FcValueBindingWeak, append);
560 }
561
562 FcBool
563 FcPatternObjectDel (FcPattern *p, FcObject object)
564 {
565     FcPatternElt   *e;
566
567     e = FcPatternObjectFindElt (p, object);
568     if (!e)
569         return FcFalse;
570
571     /* destroy value */
572     FcValueListDestroy (e->values);
573     
574     /* shuffle existing ones down */
575     memmove (e, e+1, 
576              (FcPatternElts(p) + p->num - (e + 1)) * 
577              sizeof (FcPatternElt));
578     p->num--;
579     e = FcPatternElts(p) + p->num;
580     e->object = 0;
581     e->values = NULL;
582     return FcTrue;
583 }
584
585 FcBool
586 FcPatternDel (FcPattern *p, const char *object)
587 {
588     return FcPatternObjectDel (p, FcObjectFromName (object));
589 }
590     
591 FcBool
592 FcPatternRemove (FcPattern *p, const char *object, int id)
593 {
594     FcPatternElt    *e;
595     FcValueListPtr  *prev, l;
596
597     e = FcPatternObjectFindElt (p, FcObjectFromName (object));
598     if (!e)
599         return FcFalse;
600     for (prev = &e->values; (l = *prev); prev = &l->next)
601     {
602         if (!id)
603         {
604             *prev = l->next;
605             l->next = NULL;
606             FcValueListDestroy (l);
607             if (!e->values)
608                 FcPatternDel (p, object);
609             return FcTrue;
610         }
611         id--;
612     }
613     return FcFalse;
614 }
615
616 FcBool
617 FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
618 {
619     FcValue     v;
620
621     v.type = FcTypeInteger;
622     v.u.i = i;
623     return FcPatternObjectAdd (p, object, v, FcTrue);
624 }
625
626 FcBool
627 FcPatternAddInteger (FcPattern *p, const char *object, int i)
628 {
629     return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
630 }
631
632 FcBool
633 FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
634 {
635     FcValue     v;
636
637     v.type = FcTypeDouble;
638     v.u.d = d;
639     return FcPatternObjectAdd (p, object, v, FcTrue);
640 }
641
642
643 FcBool
644 FcPatternAddDouble (FcPattern *p, const char *object, double d)
645 {
646     return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
647 }
648
649 FcBool
650 FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
651 {
652     FcValue     v;
653
654     if (!s)
655     {
656         v.type = FcTypeVoid;
657         v.u.s = 0;
658         return FcPatternObjectAdd (p, object, v, FcTrue);
659     }
660
661     v.type = FcTypeString;
662     v.u.s = FcStrStaticName(s);
663     return FcPatternObjectAdd (p, object, v, FcTrue);
664 }
665
666 FcBool
667 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
668 {
669     return FcPatternObjectAddString (p, FcObjectFromName (object), s);
670 }
671
672 FcBool
673 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
674 {
675     FcValue     v;
676
677     v.type = FcTypeMatrix;
678     v.u.m = s;
679     return FcPatternAdd (p, object, v, FcTrue);
680 }
681
682
683 FcBool
684 FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
685 {
686     FcValue     v;
687
688     v.type = FcTypeBool;
689     v.u.b = b;
690     return FcPatternObjectAdd (p, object, v, FcTrue);
691 }
692
693 FcBool
694 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
695 {
696     return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
697 }
698
699 FcBool
700 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
701 {
702     FcValue     v;
703
704     v.type = FcTypeCharSet;
705     v.u.c = (FcCharSet *)c;
706     return FcPatternAdd (p, object, v, FcTrue);
707 }
708
709 FcBool
710 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
711 {
712     FcValue     v;
713
714     v.type = FcTypeFTFace;
715     v.u.f = (void *) f;
716     return FcPatternAdd (p, object, v, FcTrue);
717 }
718
719 FcBool
720 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
721 {
722     FcValue     v;
723
724     v.type = FcTypeLangSet;
725     v.u.l = (FcLangSet *)ls;
726     return FcPatternAdd (p, object, v, FcTrue);
727 }
728
729 FcResult
730 FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
731 {
732     FcPatternElt   *e;
733     FcValueListPtr l;
734
735     e = FcPatternObjectFindElt (p, object);
736     if (!e)
737         return FcResultNoMatch;
738     for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
739     {
740         if (!id)
741         {
742             *v = FcValueCanonicalize(&l->value);
743             return FcResultMatch;
744         }
745         id--;
746     }
747     return FcResultNoId;
748 }
749
750 FcResult
751 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
752 {
753     return FcPatternObjectGet (p, FcObjectFromName (object), id, v);
754 }
755
756 FcResult
757 FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
758 {
759     FcValue     v;
760     FcResult    r;
761
762     r = FcPatternObjectGet (p, object, id, &v);
763     if (r != FcResultMatch)
764         return r;
765     switch (v.type) {
766     case FcTypeDouble:
767         *i = (int) v.u.d;
768         break;
769     case FcTypeInteger:
770         *i = v.u.i;
771         break;
772     default:
773         return FcResultTypeMismatch;
774     }
775     return FcResultMatch;
776 }
777
778 FcResult
779 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
780 {
781     return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
782 }
783     
784     
785 FcResult
786 FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
787 {
788     FcValue     v;
789     FcResult    r;
790
791     r = FcPatternObjectGet (p, object, id, &v);
792     if (r != FcResultMatch)
793         return r;
794     switch (v.type) {
795     case FcTypeDouble:
796         *d = v.u.d;
797         break;
798     case FcTypeInteger:
799         *d = (double) v.u.i;
800         break;
801     default:
802         return FcResultTypeMismatch;
803     }
804     return FcResultMatch;
805 }
806
807 FcResult
808 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
809 {
810     return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
811 }
812
813 FcResult
814 FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
815 {
816     FcValue     v;
817     FcResult    r;
818
819     r = FcPatternObjectGet (p, object, id, &v);
820     if (r != FcResultMatch)
821         return r;
822     if (v.type != FcTypeString)
823         return FcResultTypeMismatch;
824
825     *s = (FcChar8 *) v.u.s;
826     return FcResultMatch;
827 }
828
829 FcResult
830 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
831 {
832     return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
833 }
834     
835 FcResult
836 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
837 {
838     FcValue     v;
839     FcResult    r;
840
841     r = FcPatternGet (p, object, id, &v);
842     if (r != FcResultMatch)
843         return r;
844     if (v.type != FcTypeMatrix)
845         return FcResultTypeMismatch;
846     *m = (FcMatrix *)v.u.m;
847     return FcResultMatch;
848 }
849
850
851 FcResult
852 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
853 {
854     FcValue     v;
855     FcResult    r;
856
857     r = FcPatternGet (p, object, id, &v);
858     if (r != FcResultMatch)
859         return r;
860     if (v.type != FcTypeBool)
861         return FcResultTypeMismatch;
862     *b = v.u.b;
863     return FcResultMatch;
864 }
865
866 FcResult
867 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
868 {
869     FcValue     v;
870     FcResult    r;
871
872     r = FcPatternGet (p, object, id, &v);
873     if (r != FcResultMatch)
874         return r;
875     if (v.type != FcTypeCharSet)
876         return FcResultTypeMismatch;
877     *c = (FcCharSet *)v.u.c;
878     return FcResultMatch;
879 }
880
881 FcResult
882 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
883 {
884     FcValue     v;
885     FcResult    r;
886
887     r = FcPatternGet (p, object, id, &v);
888     if (r != FcResultMatch)
889         return r;
890     if (v.type != FcTypeFTFace)
891         return FcResultTypeMismatch;
892     *f = (FT_Face) v.u.f;
893     return FcResultMatch;
894 }
895
896 FcResult
897 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
898 {
899     FcValue     v;
900     FcResult    r;
901
902     r = FcPatternGet (p, object, id, &v);
903     if (r != FcResultMatch)
904         return r;
905     if (v.type != FcTypeLangSet)
906         return FcResultTypeMismatch;
907     *ls = (FcLangSet *)v.u.l;
908     return FcResultMatch;
909 }
910
911 FcPattern *
912 FcPatternDuplicate (const FcPattern *orig)
913 {
914     FcPattern       *new;
915     FcPatternElt    *e;
916     int             i;
917     FcValueListPtr  l;
918
919     new = FcPatternCreate ();
920     if (!new)
921         goto bail0;
922
923     e = FcPatternElts(orig);
924
925     for (i = 0; i < orig->num; i++)
926     {
927         for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
928             if (!FcPatternObjectAdd (new, e[i].object,
929                                      FcValueCanonicalize(&l->value),
930                                      FcTrue))
931                 goto bail1;
932     }
933
934     return new;
935
936 bail1:
937     FcPatternDestroy (new);
938 bail0:
939     return 0;
940 }
941
942 void
943 FcPatternReference (FcPattern *p)
944 {
945     if (p->ref != FC_REF_CONSTANT)
946         p->ref++;
947     else
948         FcCacheObjectReference (p);
949 }
950
951 FcPattern *
952 FcPatternVaBuild (FcPattern *orig, va_list va)
953 {
954     FcPattern   *ret;
955     
956     FcPatternVapBuild (ret, orig, va);
957     return ret;
958 }
959
960 FcPattern *
961 FcPatternBuild (FcPattern *orig, ...)
962 {
963     va_list     va;
964     
965     va_start (va, orig);
966     FcPatternVapBuild (orig, orig, va);
967     va_end (va);
968     return orig;
969 }
970
971 /*
972  * Add all of the elements in 's' to 'p'
973  */
974 FcBool
975 FcPatternAppend (FcPattern *p, FcPattern *s)
976 {
977     int             i;
978     FcPatternElt    *e;
979     FcValueListPtr  v;
980     
981     for (i = 0; i < s->num; i++)
982     {
983         e = FcPatternElts(s)+i;
984         for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
985         {
986             if (!FcPatternObjectAddWithBinding (p, e->object,
987                                                 FcValueCanonicalize(&v->value), 
988                                                 v->binding, FcTrue))
989                 return FcFalse;
990         }
991     }
992     return FcTrue;
993 }
994
995 #define OBJECT_HASH_SIZE    31
996 static struct objectBucket {
997     struct objectBucket *next;
998     FcChar32            hash;
999 } *FcObjectBuckets[OBJECT_HASH_SIZE];
1000
1001 static FcBool
1002 FcStrHashed (const FcChar8 *name)
1003 {
1004     FcChar32            hash = FcStringHash (name);
1005     struct objectBucket **p;
1006     struct objectBucket *b;
1007
1008     for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1009         if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1010             return FcTrue;
1011     return FcFalse;
1012 }
1013
1014 const FcChar8 *
1015 FcStrStaticName (const FcChar8 *name)
1016 {
1017     FcChar32            hash = FcStringHash (name);
1018     struct objectBucket **p;
1019     struct objectBucket *b;
1020     int                 size;
1021
1022     for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1023         if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1024             return (FcChar8 *) (b + 1);
1025     size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
1026     b = malloc (size + sizeof (int));
1027     /* workaround glibc bug which reads strlen in groups of 4 */
1028     FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
1029     if (!b)
1030         return NULL;
1031     b->next = 0;
1032     b->hash = hash;
1033     strcpy ((char *) (b + 1), (char *)name);
1034     *p = b;
1035     return (FcChar8 *) (b + 1);
1036 }
1037
1038 static void
1039 FcStrStaticNameFini (void)
1040 {
1041     int i, size;
1042     struct objectBucket *b, *next;
1043     char *name;
1044
1045     for (i = 0; i < OBJECT_HASH_SIZE; i++)
1046     {
1047         for (b = FcObjectBuckets[i]; b; b = next)
1048         {
1049             next = b->next;
1050             name = (char *) (b + 1);
1051             size = sizeof (struct objectBucket) + strlen (name) + 1;
1052             FcMemFree (FC_MEM_STATICSTR, size);
1053             free (b);
1054         }
1055         FcObjectBuckets[i] = 0;
1056     }
1057 }
1058
1059 void
1060 FcPatternFini (void)
1061 {
1062     FcStrStaticNameFini ();
1063     FcObjectFini ();
1064 }
1065
1066 FcBool
1067 FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
1068 {
1069     int i;
1070     FcPatternElt    *elts = FcPatternElts(pat);
1071     
1072     if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
1073         return FcFalse;
1074     if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
1075         return FcFalse;
1076     for (i = 0; i < pat->num; i++)
1077         if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
1078             return FcFalse;
1079     return FcTrue;
1080 }
1081
1082 FcPattern *
1083 FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
1084 {
1085     FcPattern       *pat_serialized;
1086     FcPatternElt    *elts = FcPatternElts (pat);
1087     FcPatternElt    *elts_serialized;
1088     FcValueList     *values_serialized;
1089     int             i;
1090
1091     pat_serialized = FcSerializePtr (serialize, pat);
1092     if (!pat_serialized)
1093         return NULL;
1094     *pat_serialized = *pat;
1095     pat_serialized->size = pat->num;
1096     pat_serialized->ref = FC_REF_CONSTANT;
1097     
1098     elts_serialized = FcSerializePtr (serialize, elts);
1099     if (!elts_serialized)
1100         return NULL;
1101     
1102     pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
1103                                                  elts_serialized);
1104
1105     for (i = 0; i < pat->num; i++)
1106     {
1107         values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
1108         if (!values_serialized)
1109             return NULL;
1110         elts_serialized[i].object = elts[i].object;
1111         elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i], 
1112                                                           values_serialized,
1113                                                           FcValueList);
1114     }
1115     if (FcDebug() & FC_DBG_CACHEV) {
1116         printf ("Raw pattern:\n");
1117         FcPatternPrint (pat);
1118         printf ("Serialized pattern:\n");
1119         FcPatternPrint (pat_serialized);
1120         printf ("\n");
1121     }
1122     return pat_serialized;
1123 }
1124
1125 FcBool
1126 FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
1127 {
1128     while (vl)
1129     {
1130         if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
1131             return FcFalse;
1132         switch (vl->value.type) {
1133         case FcTypeString:
1134             if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
1135                 return FcFalse;
1136             break;
1137         case FcTypeCharSet:
1138             if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
1139                 return FcFalse;
1140             break;
1141         case FcTypeLangSet:
1142             if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
1143                 return FcFalse;
1144             break;
1145         default:
1146             break;
1147         }
1148         vl = vl->next;
1149     }
1150     return FcTrue;
1151 }
1152
1153 FcValueList *
1154 FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
1155 {
1156     FcValueList *vl_serialized;
1157     FcChar8     *s_serialized;
1158     FcCharSet   *c_serialized;
1159     FcLangSet   *l_serialized;
1160     FcValueList *head_serialized = NULL;
1161     FcValueList *prev_serialized = NULL;
1162
1163     while (vl)
1164     {
1165         vl_serialized = FcSerializePtr (serialize, vl);
1166         if (!vl_serialized)
1167             return NULL;
1168     
1169         if (prev_serialized)
1170             prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
1171                                                           vl_serialized,
1172                                                           FcValueList);
1173         else
1174             head_serialized = vl_serialized;
1175         
1176         vl_serialized->next = NULL;
1177         vl_serialized->value = vl->value;
1178         switch (vl->value.type) {
1179         case FcTypeString:
1180             s_serialized = FcStrSerialize (serialize, vl->value.u.s);
1181             if (!s_serialized)
1182                 return NULL;
1183             vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
1184                                                              s_serialized,
1185                                                              FcChar8);
1186             break;
1187         case FcTypeCharSet:
1188             c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
1189             if (!c_serialized)
1190                 return NULL;
1191             vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
1192                                                              c_serialized,
1193                                                              FcCharSet);
1194             break;
1195         case FcTypeLangSet:
1196             l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
1197             if (!l_serialized)
1198                 return NULL;
1199             vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
1200                                                              l_serialized,
1201                                                              FcLangSet);
1202             break;
1203         default:
1204             break;
1205         }
1206         prev_serialized = vl_serialized;
1207         vl = vl->next;
1208     }
1209     return head_serialized;
1210 }
1211 #define __fcpat__
1212 #include "fcaliastail.h"
1213 #undef __fcpat__