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