]> git.wh0rd.org - fontconfig.git/blame - src/fcpat.c
Fix OOM failure case in FcPStackPush.
[fontconfig.git] / src / fcpat.c
CommitLineData
24330d27 1/*
46b51147 2 * Copyright © 2000 Keith Packard
24330d27
KP
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
f045376c 23#include "fcint.h"
24330d27
KP
24#include <stdlib.h>
25#include <string.h>
d8d73958 26#include <assert.h>
24330d27 27
9ede93f1
PL
28static FcBool
29FcStrHashed (const FcChar8 *name);
cd2ec1a9 30
24330d27
KP
31FcPattern *
32FcPatternCreate (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;
7ce19673 42 p->elts_offset = FcPtrToOffset (p, NULL);
6f6563ed 43 p->ref = 1;
24330d27
KP
44 return p;
45}
46
47void
48FcValueDestroy (FcValue v)
49{
50 switch (v.type) {
51 case FcTypeString:
9ede93f1
PL
52 if (!FcStrHashed (v.u.s))
53 FcStrFree ((FcChar8 *) v.u.s);
24330d27
KP
54 break;
55 case FcTypeMatrix:
4262e0b3 56 FcMatrixFree ((FcMatrix *) v.u.m);
24330d27
KP
57 break;
58 case FcTypeCharSet:
4262e0b3 59 FcCharSetDestroy ((FcCharSet *) v.u.c);
24330d27 60 break;
d8d73958 61 case FcTypeLangSet:
4262e0b3 62 FcLangSetDestroy ((FcLangSet *) v.u.l);
d8d73958 63 break;
24330d27
KP
64 default:
65 break;
66 }
67}
68
4262e0b3
PL
69FcValue
70FcValueCanonicalize (const FcValue *v)
71{
7ce19673 72 FcValue new;
4262e0b3 73
7ce19673
KP
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;
4262e0b3 91 }
7ce19673 92 return new;
4262e0b3
PL
93}
94
24330d27
KP
95FcValue
96FcValueSave (FcValue v)
97{
98 switch (v.type) {
99 case FcTypeString:
4262e0b3
PL
100 v.u.s = FcStrCopy (v.u.s);
101 if (!v.u.s)
24330d27
KP
102 v.type = FcTypeVoid;
103 break;
104 case FcTypeMatrix:
4262e0b3
PL
105 v.u.m = FcMatrixCopy (v.u.m);
106 if (!v.u.m)
24330d27
KP
107 v.type = FcTypeVoid;
108 break;
109 case FcTypeCharSet:
4262e0b3
PL
110 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
111 if (!v.u.c)
24330d27
KP
112 v.type = FcTypeVoid;
113 break;
d8d73958 114 case FcTypeLangSet:
4262e0b3
PL
115 v.u.l = FcLangSetCopy (v.u.l);
116 if (!v.u.l)
d8d73958
KP
117 v.type = FcTypeVoid;
118 break;
24330d27
KP
119 default:
120 break;
121 }
122 return v;
123}
124
125void
cd2ec1a9 126FcValueListDestroy (FcValueListPtr l)
24330d27 127{
cd2ec1a9 128 FcValueListPtr next;
7ce19673 129 for (; l; l = next)
24330d27 130 {
7ce19673 131 switch (l->value.type) {
24330d27 132 case FcTypeString:
7ce19673
KP
133 if (!FcStrHashed ((FcChar8 *)l->value.u.s))
134 FcStrFree ((FcChar8 *)l->value.u.s);
24330d27
KP
135 break;
136 case FcTypeMatrix:
7ce19673 137 FcMatrixFree ((FcMatrix *)l->value.u.m);
24330d27
KP
138 break;
139 case FcTypeCharSet:
cd2ec1a9 140 FcCharSetDestroy
7ce19673 141 ((FcCharSet *) (l->value.u.c));
24330d27 142 break;
d8d73958 143 case FcTypeLangSet:
cd2ec1a9 144 FcLangSetDestroy
7ce19673 145 ((FcLangSet *) (l->value.u.l));
d8d73958 146 break;
24330d27
KP
147 default:
148 break;
149 }
7ce19673 150 next = FcValueListNext(l);
24330d27 151 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
7ce19673 152 free(l);
24330d27
KP
153 }
154}
155
0ab36ca8
KP
156FcBool
157FcValueEqual (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:
4262e0b3 182 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
0ab36ca8
KP
183 case FcTypeBool:
184 return va.u.b == vb.u.b;
185 case FcTypeMatrix:
4262e0b3 186 return FcMatrixEqual (va.u.m, vb.u.m);
0ab36ca8 187 case FcTypeCharSet:
4262e0b3 188 return FcCharSetEqual (va.u.c, vb.u.c);
be094850
KP
189 case FcTypeFTFace:
190 return va.u.f == vb.u.f;
d8d73958 191 case FcTypeLangSet:
4262e0b3 192 return FcLangSetEqual (va.u.l, vb.u.l);
0ab36ca8
KP
193 }
194 return FcFalse;
195}
196
d0f07b8d
KP
197static FcChar32
198FcDoubleHash (double d)
199{
200 if (d < 0)
201 d = -d;
202 if (d > 0xffffffff)
203 d = 0xffffffff;
204 return (FcChar32) d;
205}
206
7f37423d 207FcChar32
d0f07b8d
KP
208FcStringHash (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
219static FcChar32
efb11b36 220FcValueHash (const FcValue *v)
d0f07b8d 221{
efb11b36 222 switch (fc_storage_type(v)) {
d0f07b8d
KP
223 case FcTypeVoid:
224 return 0;
225 case FcTypeInteger:
efb11b36 226 return (FcChar32) v->u.i;
d0f07b8d 227 case FcTypeDouble:
efb11b36 228 return FcDoubleHash (v->u.d);
d0f07b8d 229 case FcTypeString:
efb11b36 230 return FcStringHash (fc_value_string(v));
d0f07b8d 231 case FcTypeBool:
efb11b36 232 return (FcChar32) v->u.b;
d0f07b8d 233 case FcTypeMatrix:
efb11b36
PL
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));
d0f07b8d 238 case FcTypeCharSet:
efb11b36 239 return (FcChar32) fc_value_charset(v)->num;
d0f07b8d 240 case FcTypeFTFace:
efb11b36
PL
241 return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
242 FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
d8d73958 243 case FcTypeLangSet:
efb11b36 244 return FcLangSetHash (fc_value_langset(v));
d0f07b8d
KP
245 }
246 return FcFalse;
247}
248
0ab36ca8 249static FcBool
cd2ec1a9 250FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
0ab36ca8 251{
7ce19673 252 if (la == lb)
d8d73958
KP
253 return FcTrue;
254
7ce19673 255 while (la && lb)
0ab36ca8 256 {
7ce19673 257 if (!FcValueEqual (la->value, lb->value))
0ab36ca8 258 return FcFalse;
7ce19673
KP
259 la = FcValueListNext(la);
260 lb = FcValueListNext(lb);
0ab36ca8 261 }
7ce19673 262 if (la || lb)
0ab36ca8
KP
263 return FcFalse;
264 return FcTrue;
265}
266
d0f07b8d 267static FcChar32
cd2ec1a9 268FcValueListHash (FcValueListPtr l)
d0f07b8d
KP
269{
270 FcChar32 hash = 0;
271
7ce19673 272 for (; l; l = FcValueListNext(l))
d0f07b8d 273 {
7ce19673 274 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value);
d0f07b8d
KP
275 }
276 return hash;
277}
278
24330d27
KP
279void
280FcPatternDestroy (FcPattern *p)
281{
282 int i;
7ce19673 283 FcPatternElt *elts;
24330d27 284
9e612141
KP
285 if (p->ref == FC_REF_CONSTANT)
286 {
287 FcCacheObjectDereference (p);
288 return;
289 }
290
291 if (--p->ref > 0)
6f6563ed
KP
292 return;
293
7ce19673 294 elts = FcPatternElts (p);
24330d27 295 for (i = 0; i < p->num; i++)
7ce19673 296 FcValueListDestroy (FcPatternEltValues(&elts[i]));
24330d27 297
7ce19673
KP
298 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
299 free (elts);
24330d27
KP
300 FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
301 free (p);
302}
303
e9be9cd1 304static int
7ce19673 305FcPatternObjectPosition (const FcPattern *p, FcObject object)
24330d27 306{
e9be9cd1 307 int low, high, mid, c;
7ce19673 308 FcPatternElt *elts = FcPatternElts(p);
0ab36ca8 309
0ab36ca8 310 low = 0;
e9be9cd1
KP
311 high = p->num - 1;
312 c = 1;
313 mid = 0;
314 while (low <= high)
24330d27 315 {
e9be9cd1 316 mid = (low + high) >> 1;
7ce19673 317 c = elts[mid].object - object;
e9be9cd1
KP
318 if (c == 0)
319 return mid;
320 if (c < 0)
321 low = mid + 1;
0ab36ca8 322 else
e9be9cd1 323 high = mid - 1;
24330d27 324 }
e9be9cd1
KP
325 if (c < 0)
326 mid++;
327 return -(mid + 1);
328}
24330d27 329
e9be9cd1 330FcPatternElt *
7ce19673 331FcPatternObjectFindElt (const FcPattern *p, FcObject object)
e9be9cd1 332{
7ce19673 333 int i = FcPatternObjectPosition (p, object);
e9be9cd1 334 if (i < 0)
0ab36ca8 335 return 0;
7ce19673 336 return &FcPatternElts(p)[i];
e9be9cd1 337}
24330d27 338
e9be9cd1 339FcPatternElt *
7ce19673 340FcPatternObjectInsertElt (FcPattern *p, FcObject object)
e9be9cd1
KP
341{
342 int i;
343 FcPatternElt *e;
344
7ce19673 345 i = FcPatternObjectPosition (p, object);
e9be9cd1 346 if (i < 0)
24330d27 347 {
e9be9cd1
KP
348 i = -i - 1;
349
cd2ec1a9 350 /* reallocate array */
e9be9cd1 351 if (p->num + 1 >= p->size)
24330d27 352 {
e9be9cd1 353 int s = p->size + 16;
7ce19673 354 if (p->size)
cd2ec1a9 355 {
7ce19673 356 FcPatternElt *e0 = FcPatternElts(p);
cd2ec1a9
PL
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 }
e9be9cd1
KP
365 else
366 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
367 if (!e)
368 return FcFalse;
7ce19673 369 p->elts_offset = FcPtrToOffset (p, e);
e9be9cd1
KP
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 {
7ce19673
KP
375 e[p->size].object = 0;
376 e[p->size].values = NULL;
e9be9cd1
KP
377 p->size++;
378 }
24330d27 379 }
e9be9cd1 380
7ce19673 381 e = FcPatternElts(p);
e9be9cd1 382 /* move elts up */
7ce19673
KP
383 memmove (e + i + 1,
384 e + i,
e9be9cd1
KP
385 sizeof (FcPatternElt) *
386 (p->num - i));
387
388 /* bump count */
389 p->num++;
390
7ce19673
KP
391 e[i].object = object;
392 e[i].values = NULL;
24330d27
KP
393 }
394
7ce19673 395 return FcPatternElts(p) + i;
24330d27
KP
396}
397
0ab36ca8 398FcBool
e9be9cd1 399FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
0ab36ca8
KP
400{
401 int i;
7ce19673 402 FcPatternElt *pae, *pbe;
0ab36ca8 403
bd724c85
KP
404 if (pa == pb)
405 return FcTrue;
406
0ab36ca8
KP
407 if (pa->num != pb->num)
408 return FcFalse;
7ce19673
KP
409 pae = FcPatternElts(pa);
410 pbe = FcPatternElts(pb);
0ab36ca8
KP
411 for (i = 0; i < pa->num; i++)
412 {
7ce19673 413 if (pae[i].object != pbe[i].object)
0ab36ca8 414 return FcFalse;
7ce19673
KP
415 if (!FcValueListEqual (FcPatternEltValues(&pae[i]),
416 FcPatternEltValues(&pbe[i])))
0ab36ca8
KP
417 return FcFalse;
418 }
419 return FcTrue;
420}
421
d0f07b8d
KP
422FcChar32
423FcPatternHash (const FcPattern *p)
424{
425 int i;
426 FcChar32 h = 0;
7ce19673 427 FcPatternElt *pe = FcPatternElts(p);
d0f07b8d
KP
428
429 for (i = 0; i < p->num; i++)
430 {
431 h = (((h << 1) | (h >> 31)) ^
7ce19673
KP
432 pe[i].object ^
433 FcValueListHash (FcPatternEltValues(&pe[i])));
d0f07b8d
KP
434 }
435 return h;
436}
437
e9be9cd1 438FcBool
cd2ec1a9 439FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
e9be9cd1
KP
440{
441 FcPatternElt *ea, *eb;
442 int i;
443
444 for (i = 0; i < os->nobject; i++)
445 {
7ce19673
KP
446 FcObject object = FcObjectFromName (os->objects[i]);
447 ea = FcPatternObjectFindElt (pai, object);
448 eb = FcPatternObjectFindElt (pbi, object);
e9be9cd1
KP
449 if (ea)
450 {
451 if (!eb)
452 return FcFalse;
7ce19673 453 if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
e9be9cd1
KP
454 return FcFalse;
455 }
456 else
457 {
458 if (eb)
459 return FcFalse;
460 }
461 }
462 return FcTrue;
463}
464
24330d27 465FcBool
7ce19673
KP
466FcPatternObjectAddWithBinding (FcPattern *p,
467 FcObject object,
468 FcValue value,
469 FcValueBinding binding,
470 FcBool append)
24330d27
KP
471{
472 FcPatternElt *e;
cd2ec1a9 473 FcValueListPtr new, *prev;
24330d27 474
d8d73958
KP
475 if (p->ref == FC_REF_CONSTANT)
476 goto bail0;
477
7ce19673
KP
478 new = malloc (sizeof (FcValueList));
479 if (!new)
24330d27
KP
480 goto bail0;
481
7ce19673 482 memset(new, 0, sizeof (FcValueList));
24330d27
KP
483 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
484 /* dup string */
575a37b7
PL
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);
24330d27
KP
493 if (value.type == FcTypeVoid)
494 goto bail1;
495
7ce19673
KP
496 /*
497 * Make sure the stored type is valid for built-in objects
498 */
499 if (!FcObjectValidType (object, value.type))
bc5e487f
KP
500 {
501 if (FcDebug() & FC_DBG_OBJTYPES)
502 {
503 printf ("FcPattern object %s does not accept value ",
504 FcObjectName (object));
505 FcValuePrint (value);
506 }
7ce19673 507 goto bail1;
bc5e487f 508 }
7ce19673
KP
509
510 new->value = value;
511 new->binding = binding;
512 new->next = NULL;
24330d27 513
7ce19673 514 e = FcPatternObjectInsertElt (p, object);
24330d27
KP
515 if (!e)
516 goto bail2;
517
518 if (append)
519 {
7ce19673 520 for (prev = &e->values; *prev; prev = &(*prev)->next)
cd2ec1a9 521 ;
24330d27
KP
522 *prev = new;
523 }
524 else
525 {
7ce19673 526 new->next = e->values;
24330d27
KP
527 e->values = new;
528 }
529
530 return FcTrue;
531
532bail2:
7ce19673 533 FcValueDestroy (value);
24330d27
KP
534bail1:
535 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
7ce19673 536 free (new);
24330d27
KP
537bail0:
538 return FcFalse;
539}
540
7ce19673
KP
541FcBool
542FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
543{
544 return FcPatternObjectAddWithBinding (p, object,
545 value, FcValueBindingStrong, append);
546}
547
82f4243f
KP
548FcBool
549FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
550{
7ce19673
KP
551 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
552 value, FcValueBindingStrong, append);
82f4243f
KP
553}
554
555FcBool
556FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
557{
7ce19673
KP
558 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
559 value, FcValueBindingWeak, append);
82f4243f
KP
560}
561
24330d27 562FcBool
7ce19673 563FcPatternObjectDel (FcPattern *p, FcObject object)
24330d27
KP
564{
565 FcPatternElt *e;
24330d27 566
7ce19673 567 e = FcPatternObjectFindElt (p, object);
24330d27
KP
568 if (!e)
569 return FcFalse;
570
24330d27
KP
571 /* destroy value */
572 FcValueListDestroy (e->values);
573
574 /* shuffle existing ones down */
cd2ec1a9 575 memmove (e, e+1,
7ce19673 576 (FcPatternElts(p) + p->num - (e + 1)) *
cd2ec1a9 577 sizeof (FcPatternElt));
24330d27 578 p->num--;
7ce19673
KP
579 e = FcPatternElts(p) + p->num;
580 e->object = 0;
581 e->values = NULL;
24330d27
KP
582 return FcTrue;
583}
584
7ce19673
KP
585FcBool
586FcPatternDel (FcPattern *p, const char *object)
587{
588 return FcPatternObjectDel (p, FcObjectFromName (object));
589}
590
4f27c1c0
KP
591FcBool
592FcPatternRemove (FcPattern *p, const char *object, int id)
593{
cd2ec1a9
PL
594 FcPatternElt *e;
595 FcValueListPtr *prev, l;
4f27c1c0 596
7ce19673 597 e = FcPatternObjectFindElt (p, FcObjectFromName (object));
4f27c1c0
KP
598 if (!e)
599 return FcFalse;
7ce19673 600 for (prev = &e->values; (l = *prev); prev = &l->next)
4f27c1c0
KP
601 {
602 if (!id)
603 {
7ce19673
KP
604 *prev = l->next;
605 l->next = NULL;
4f27c1c0 606 FcValueListDestroy (l);
7ce19673 607 if (!e->values)
4f27c1c0
KP
608 FcPatternDel (p, object);
609 return FcTrue;
610 }
611 id--;
612 }
613 return FcFalse;
614}
615
24330d27 616FcBool
7ce19673 617FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
24330d27
KP
618{
619 FcValue v;
620
621 v.type = FcTypeInteger;
622 v.u.i = i;
7ce19673 623 return FcPatternObjectAdd (p, object, v, FcTrue);
24330d27
KP
624}
625
626FcBool
7ce19673
KP
627FcPatternAddInteger (FcPattern *p, const char *object, int i)
628{
629 return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
630}
631
632FcBool
633FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
24330d27
KP
634{
635 FcValue v;
636
637 v.type = FcTypeDouble;
638 v.u.d = d;
7ce19673 639 return FcPatternObjectAdd (p, object, v, FcTrue);
24330d27
KP
640}
641
642
643FcBool
7ce19673
KP
644FcPatternAddDouble (FcPattern *p, const char *object, double d)
645{
646 return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
647}
648
649FcBool
650FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
24330d27
KP
651{
652 FcValue v;
653
204da5a8
PL
654 if (!s)
655 {
656 v.type = FcTypeVoid;
657 v.u.s = 0;
7ce19673 658 return FcPatternObjectAdd (p, object, v, FcTrue);
204da5a8
PL
659 }
660
24330d27 661 v.type = FcTypeString;
7f37423d 662 v.u.s = FcStrStaticName(s);
7ce19673
KP
663 return FcPatternObjectAdd (p, object, v, FcTrue);
664}
665
666FcBool
667FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
668{
669 return FcPatternObjectAddString (p, FcObjectFromName (object), s);
24330d27
KP
670}
671
672FcBool
673FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
674{
675 FcValue v;
676
677 v.type = FcTypeMatrix;
4262e0b3 678 v.u.m = s;
24330d27
KP
679 return FcPatternAdd (p, object, v, FcTrue);
680}
681
682
683FcBool
7ce19673 684FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
24330d27
KP
685{
686 FcValue v;
687
688 v.type = FcTypeBool;
689 v.u.b = b;
7ce19673
KP
690 return FcPatternObjectAdd (p, object, v, FcTrue);
691}
692
693FcBool
694FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
695{
696 return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
24330d27
KP
697}
698
699FcBool
700FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
701{
702 FcValue v;
703
704 v.type = FcTypeCharSet;
4262e0b3 705 v.u.c = (FcCharSet *)c;
24330d27
KP
706 return FcPatternAdd (p, object, v, FcTrue);
707}
708
be094850
KP
709FcBool
710FcPatternAddFTFace (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
d8d73958
KP
719FcBool
720FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
721{
722 FcValue v;
723
724 v.type = FcTypeLangSet;
4262e0b3 725 v.u.l = (FcLangSet *)ls;
d8d73958
KP
726 return FcPatternAdd (p, object, v, FcTrue);
727}
728
24330d27 729FcResult
7ce19673 730FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
24330d27
KP
731{
732 FcPatternElt *e;
cd2ec1a9 733 FcValueListPtr l;
24330d27 734
7ce19673 735 e = FcPatternObjectFindElt (p, object);
24330d27
KP
736 if (!e)
737 return FcResultNoMatch;
7ce19673 738 for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
24330d27
KP
739 {
740 if (!id)
741 {
7ce19673 742 *v = FcValueCanonicalize(&l->value);
24330d27
KP
743 return FcResultMatch;
744 }
745 id--;
746 }
747 return FcResultNoId;
748}
749
750FcResult
7ce19673
KP
751FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
752{
753 return FcPatternObjectGet (p, FcObjectFromName (object), id, v);
754}
755
756FcResult
757FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
24330d27
KP
758{
759 FcValue v;
760 FcResult r;
761
7ce19673 762 r = FcPatternObjectGet (p, object, id, &v);
24330d27
KP
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
778FcResult
7ce19673
KP
779FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
780{
781 return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
782}
783
784
785FcResult
786FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
24330d27
KP
787{
788 FcValue v;
789 FcResult r;
790
7ce19673 791 r = FcPatternObjectGet (p, object, id, &v);
24330d27
KP
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
807FcResult
7ce19673
KP
808FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
809{
810 return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
811}
812
813FcResult
814FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
24330d27
KP
815{
816 FcValue v;
817 FcResult r;
818
7ce19673 819 r = FcPatternObjectGet (p, object, id, &v);
24330d27
KP
820 if (r != FcResultMatch)
821 return r;
822 if (v.type != FcTypeString)
823 return FcResultTypeMismatch;
e77c1718 824
4262e0b3 825 *s = (FcChar8 *) v.u.s;
24330d27
KP
826 return FcResultMatch;
827}
828
7ce19673
KP
829FcResult
830FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
831{
832 return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
833}
834
24330d27 835FcResult
bff80114 836FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
24330d27
KP
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;
4262e0b3 846 *m = (FcMatrix *)v.u.m;
24330d27
KP
847 return FcResultMatch;
848}
849
850
851FcResult
bff80114 852FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
24330d27
KP
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
866FcResult
bff80114 867FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
24330d27
KP
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;
4262e0b3 877 *c = (FcCharSet *)v.u.c;
24330d27
KP
878 return FcResultMatch;
879}
880
be094850 881FcResult
bff80114 882FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
be094850
KP
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
d8d73958 896FcResult
bff80114 897FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
d8d73958
KP
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;
4262e0b3 907 *ls = (FcLangSet *)v.u.l;
d8d73958
KP
908 return FcResultMatch;
909}
910
24330d27 911FcPattern *
bff80114 912FcPatternDuplicate (const FcPattern *orig)
24330d27
KP
913{
914 FcPattern *new;
cd2ec1a9 915 FcPatternElt *e;
24330d27 916 int i;
cd2ec1a9 917 FcValueListPtr l;
24330d27
KP
918
919 new = FcPatternCreate ();
920 if (!new)
921 goto bail0;
922
7ce19673 923 e = FcPatternElts(orig);
cd2ec1a9 924
24330d27
KP
925 for (i = 0; i < orig->num; i++)
926 {
7ce19673 927 for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
9b74b78f
SK
928 {
929 if (!FcPatternObjectAddWithBinding (new, e[i].object,
930 FcValueCanonicalize(&l->value),
931 l->binding,
932 FcTrue))
24330d27 933 goto bail1;
9b74b78f
SK
934
935 }
24330d27
KP
936 }
937
938 return new;
939
940bail1:
941 FcPatternDestroy (new);
942bail0:
943 return 0;
944}
945
6f6563ed
KP
946void
947FcPatternReference (FcPattern *p)
948{
d8d73958
KP
949 if (p->ref != FC_REF_CONSTANT)
950 p->ref++;
9e612141
KP
951 else
952 FcCacheObjectReference (p);
6f6563ed
KP
953}
954
24330d27
KP
955FcPattern *
956FcPatternVaBuild (FcPattern *orig, va_list va)
957{
958 FcPattern *ret;
959
960 FcPatternVapBuild (ret, orig, va);
961 return ret;
962}
963
964FcPattern *
965FcPatternBuild (FcPattern *orig, ...)
966{
967 va_list va;
968
969 va_start (va, orig);
970 FcPatternVapBuild (orig, orig, va);
971 va_end (va);
972 return orig;
973}
4f27c1c0
KP
974
975/*
976 * Add all of the elements in 's' to 'p'
977 */
978FcBool
979FcPatternAppend (FcPattern *p, FcPattern *s)
980{
981 int i;
982 FcPatternElt *e;
cd2ec1a9 983 FcValueListPtr v;
4f27c1c0
KP
984
985 for (i = 0; i < s->num; i++)
986 {
7ce19673
KP
987 e = FcPatternElts(s)+i;
988 for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
4f27c1c0 989 {
7ce19673
KP
990 if (!FcPatternObjectAddWithBinding (p, e->object,
991 FcValueCanonicalize(&v->value),
992 v->binding, FcTrue))
4f27c1c0
KP
993 return FcFalse;
994 }
995 }
996 return FcTrue;
997}
998
4262e0b3 999#define OBJECT_HASH_SIZE 31
8245771d 1000static struct objectBucket {
4262e0b3
PL
1001 struct objectBucket *next;
1002 FcChar32 hash;
8245771d 1003} *FcObjectBuckets[OBJECT_HASH_SIZE];
4262e0b3 1004
9ede93f1
PL
1005static FcBool
1006FcStrHashed (const FcChar8 *name)
1007{
1008 FcChar32 hash = FcStringHash (name);
1009 struct objectBucket **p;
1010 struct objectBucket *b;
1011
1012 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1013 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1014 return FcTrue;
1015 return FcFalse;
1016}
1017
8245771d
PL
1018const FcChar8 *
1019FcStrStaticName (const FcChar8 *name)
4262e0b3 1020{
8245771d
PL
1021 FcChar32 hash = FcStringHash (name);
1022 struct objectBucket **p;
1023 struct objectBucket *b;
1024 int size;
4262e0b3 1025
8245771d
PL
1026 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1027 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1028 return (FcChar8 *) (b + 1);
1029 size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
23787a8f
PL
1030 b = malloc (size + sizeof (int));
1031 /* workaround glibc bug which reads strlen in groups of 4 */
1032 FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
4262e0b3
PL
1033 if (!b)
1034 return NULL;
1035 b->next = 0;
1036 b->hash = hash;
8245771d 1037 strcpy ((char *) (b + 1), (char *)name);
4262e0b3 1038 *p = b;
8245771d 1039 return (FcChar8 *) (b + 1);
4262e0b3
PL
1040}
1041
1042static void
7f37423d 1043FcStrStaticNameFini (void)
cd2ec1a9 1044{
4262e0b3
PL
1045 int i, size;
1046 struct objectBucket *b, *next;
1047 char *name;
1048
1049 for (i = 0; i < OBJECT_HASH_SIZE; i++)
cd2ec1a9 1050 {
4262e0b3
PL
1051 for (b = FcObjectBuckets[i]; b; b = next)
1052 {
1053 next = b->next;
1054 name = (char *) (b + 1);
1055 size = sizeof (struct objectBucket) + strlen (name) + 1;
1056 FcMemFree (FC_MEM_STATICSTR, size);
1057 free (b);
1058 }
1059 FcObjectBuckets[i] = 0;
cd2ec1a9
PL
1060 }
1061}
1062
4262e0b3
PL
1063void
1064FcPatternFini (void)
1065{
7f37423d 1066 FcStrStaticNameFini ();
09f9f6f6 1067 FcObjectFini ();
4262e0b3
PL
1068}
1069
7ce19673
KP
1070FcBool
1071FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
4262e0b3 1072{
7ce19673
KP
1073 int i;
1074 FcPatternElt *elts = FcPatternElts(pat);
4262e0b3 1075
7ce19673
KP
1076 if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
1077 return FcFalse;
1078 if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
1079 return FcFalse;
1080 for (i = 0; i < pat->num; i++)
1081 if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
1082 return FcFalse;
1083 return FcTrue;
4262e0b3
PL
1084}
1085
cd2ec1a9 1086FcPattern *
7ce19673 1087FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
cd2ec1a9 1088{
7ce19673
KP
1089 FcPattern *pat_serialized;
1090 FcPatternElt *elts = FcPatternElts (pat);
1091 FcPatternElt *elts_serialized;
1092 FcValueList *values_serialized;
1093 int i;
212c9f43 1094
7ce19673
KP
1095 pat_serialized = FcSerializePtr (serialize, pat);
1096 if (!pat_serialized)
1097 return NULL;
1098 *pat_serialized = *pat;
1099 pat_serialized->size = pat->num;
1100 pat_serialized->ref = FC_REF_CONSTANT;
1101
1102 elts_serialized = FcSerializePtr (serialize, elts);
1103 if (!elts_serialized)
1104 return NULL;
1105
1106 pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
1107 elts_serialized);
212c9f43 1108
7ce19673 1109 for (i = 0; i < pat->num; i++)
cd2ec1a9 1110 {
7ce19673
KP
1111 values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
1112 if (!values_serialized)
1113 return NULL;
1114 elts_serialized[i].object = elts[i].object;
1115 elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
1116 values_serialized,
1117 FcValueList);
cd2ec1a9 1118 }
c0288648
KP
1119 if (FcDebug() & FC_DBG_CACHEV) {
1120 printf ("Raw pattern:\n");
1121 FcPatternPrint (pat);
1122 printf ("Serialized pattern:\n");
1123 FcPatternPrint (pat_serialized);
1124 printf ("\n");
1125 }
7ce19673 1126 return pat_serialized;
4262e0b3 1127}
212c9f43 1128
7ce19673
KP
1129FcBool
1130FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
4262e0b3 1131{
7ce19673 1132 while (vl)
212c9f43 1133 {
7ce19673
KP
1134 if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
1135 return FcFalse;
1136 switch (vl->value.type) {
1137 case FcTypeString:
1138 if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
1139 return FcFalse;
1140 break;
4262e0b3 1141 case FcTypeCharSet:
7ce19673
KP
1142 if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
1143 return FcFalse;
4262e0b3
PL
1144 break;
1145 case FcTypeLangSet:
7ce19673
KP
1146 if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
1147 return FcFalse;
4262e0b3 1148 break;
4262e0b3
PL
1149 default:
1150 break;
1151 }
7ce19673 1152 vl = vl->next;
4262e0b3 1153 }
212c9f43
PL
1154 return FcTrue;
1155}
1156
7ce19673
KP
1157FcValueList *
1158FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
212c9f43 1159{
7ce19673
KP
1160 FcValueList *vl_serialized;
1161 FcChar8 *s_serialized;
1162 FcCharSet *c_serialized;
1163 FcLangSet *l_serialized;
1164 FcValueList *head_serialized = NULL;
1165 FcValueList *prev_serialized = NULL;
4262e0b3 1166
7ce19673 1167 while (vl)
0fa680f0 1168 {
7ce19673
KP
1169 vl_serialized = FcSerializePtr (serialize, vl);
1170 if (!vl_serialized)
1171 return NULL;
1172
1173 if (prev_serialized)
1174 prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
1175 vl_serialized,
1176 FcValueList);
1177 else
1178 head_serialized = vl_serialized;
1179
1180 vl_serialized->next = NULL;
2b77216e 1181 vl_serialized->value.type = vl->value.type;
7ce19673 1182 switch (vl->value.type) {
2b77216e
KP
1183 case FcTypeInteger:
1184 vl_serialized->value.u.i = vl->value.u.i;
1185 break;
1186 case FcTypeDouble:
1187 vl_serialized->value.u.d = vl->value.u.d;
1188 break;
7ce19673
KP
1189 case FcTypeString:
1190 s_serialized = FcStrSerialize (serialize, vl->value.u.s);
1191 if (!s_serialized)
1192 return NULL;
1193 vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
1194 s_serialized,
1195 FcChar8);
1196 break;
2b77216e
KP
1197 case FcTypeBool:
1198 vl_serialized->value.u.b = vl->value.u.b;
1199 break;
1200 case FcTypeMatrix:
1201 /* can't happen */
1202 break;
7ce19673
KP
1203 case FcTypeCharSet:
1204 c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
1205 if (!c_serialized)
1206 return NULL;
1207 vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
1208 c_serialized,
1209 FcCharSet);
1210 break;
2b77216e
KP
1211 case FcTypeFTFace:
1212 /* can't happen */
1213 break;
7ce19673
KP
1214 case FcTypeLangSet:
1215 l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
1216 if (!l_serialized)
1217 return NULL;
1218 vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
1219 l_serialized,
1220 FcLangSet);
1221 break;
1222 default:
1223 break;
0fa680f0 1224 }
e9a564e2 1225 prev_serialized = vl_serialized;
7ce19673 1226 vl = vl->next;
0fa680f0 1227 }
7ce19673 1228 return head_serialized;
e1b9d091 1229}
23816bf9
KP
1230#define __fcpat__
1231#include "fcaliastail.h"
1232#undef __fcpat__