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