]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
Fix problem dating back at least to 2.3.2 where globs weren't being applied
[fontconfig.git] / src / fcpat.c
1 /*
2 * $RCSId: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi Exp $
3 *
4 * Copyright © 2000 Keith Packard
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include "fcint.h"
29
30 static FcPattern ** _fcPatterns = 0;
31 static int fcpattern_bank_count = 0, fcpattern_ptr, fcpattern_count;
32 FcPatternElt ** _fcPatternElts = 0;
33 static int fcpatternelt_ptr, fcpatternelt_count;
34 FcValueList ** _fcValueLists = 0;
35 static int fcvaluelist_bank_count = 0, fcvaluelist_ptr, fcvaluelist_count;
36
37 static FcPatternEltPtr
38 FcPatternEltPtrCreateDynamic (FcPatternElt * e);
39
40 /* If you are trying to duplicate an FcPattern which will be used for
41 * rendering, be aware that (internally) you also have to use
42 * FcPatternTransferFullFname to transfer the associated filename. If
43 * you are copying the font (externally) using FcPatternGetString,
44 * then everything's fine; this caveat only applies if you're copying
45 * the bits individually. */
46
47 FcPattern *
48 FcPatternCreate (void)
49 {
50 FcPattern *p;
51
52 p = (FcPattern *) malloc (sizeof (FcPattern));
53 if (!p)
54 return 0;
55 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
56 p->num = 0;
57 p->size = 0;
58 p->elts = FcPatternEltPtrCreateDynamic(0);
59 p->bank = FC_BANK_DYNAMIC;
60 p->ref = 1;
61 return p;
62 }
63
64 void
65 FcValueDestroy (FcValue v)
66 {
67 switch (v.type) {
68 case FcTypeString:
69 FcStrFree ((FcChar8 *) v.u.s);
70 break;
71 case FcTypeMatrix:
72 FcMatrixFree ((FcMatrix *) v.u.m);
73 break;
74 case FcTypeCharSet:
75 FcCharSetDestroy ((FcCharSet *) v.u.c);
76 break;
77 case FcTypeLangSet:
78 FcLangSetDestroy ((FcLangSet *) v.u.l);
79 break;
80 default:
81 break;
82 }
83 }
84
85 FcValue
86 FcValueCanonicalize (const FcValue *v)
87 {
88 if (v->type & FC_STORAGE_STATIC)
89 {
90 FcValue new = *v;
91
92 switch (v->type & ~FC_STORAGE_STATIC)
93 {
94 case FcTypeString:
95 new.u.s = fc_value_string(v);
96 new.type = FcTypeString;
97 break;
98 case FcTypeCharSet:
99 new.u.c = fc_value_charset(v);
100 new.type = FcTypeCharSet;
101 break;
102 case FcTypeLangSet:
103 new.u.l = fc_value_langset(v);
104 new.type = FcTypeLangSet;
105 break;
106 }
107 return new;
108 }
109 return *v;
110 }
111
112 FcValue
113 FcValueSave (FcValue v)
114 {
115 switch (v.type) {
116 case FcTypeString:
117 v.u.s = FcStrCopy (v.u.s);
118 if (!v.u.s)
119 v.type = FcTypeVoid;
120 break;
121 case FcTypeMatrix:
122 v.u.m = FcMatrixCopy (v.u.m);
123 if (!v.u.m)
124 v.type = FcTypeVoid;
125 break;
126 case FcTypeCharSet:
127 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
128 if (!v.u.c)
129 v.type = FcTypeVoid;
130 break;
131 case FcTypeLangSet:
132 v.u.l = FcLangSetCopy (v.u.l);
133 if (!v.u.l)
134 v.type = FcTypeVoid;
135 break;
136 default:
137 break;
138 }
139 return v;
140 }
141
142 void
143 FcValueListDestroy (FcValueListPtr l)
144 {
145 FcValueListPtr next;
146 for (; FcValueListPtrU(l); l = next)
147 {
148 switch (FcValueListPtrU(l)->value.type) {
149 case FcTypeString:
150 FcStrFree ((FcChar8 *)FcValueListPtrU(l)->value.u.s);
151 break;
152 case FcTypeMatrix:
153 FcMatrixFree ((FcMatrix *)FcValueListPtrU(l)->value.u.m);
154 break;
155 case FcTypeCharSet:
156 FcCharSetDestroy
157 ((FcCharSet *) (FcValueListPtrU(l)->value.u.c));
158 break;
159 case FcTypeLangSet:
160 FcLangSetDestroy
161 ((FcLangSet *) (FcValueListPtrU(l)->value.u.l));
162 break;
163 default:
164 break;
165 }
166 next = FcValueListPtrU(l)->next;
167 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
168 if (l.bank == FC_BANK_DYNAMIC)
169 free(l.u.dyn);
170 }
171 }
172
173 FcBool
174 FcValueEqual (FcValue va, FcValue vb)
175 {
176 if (va.type != vb.type)
177 {
178 if (va.type == FcTypeInteger)
179 {
180 va.type = FcTypeDouble;
181 va.u.d = va.u.i;
182 }
183 if (vb.type == FcTypeInteger)
184 {
185 vb.type = FcTypeDouble;
186 vb.u.d = vb.u.i;
187 }
188 if (va.type != vb.type)
189 return FcFalse;
190 }
191 switch (va.type) {
192 case FcTypeVoid:
193 return FcTrue;
194 case FcTypeInteger:
195 return va.u.i == vb.u.i;
196 case FcTypeDouble:
197 return va.u.d == vb.u.d;
198 case FcTypeString:
199 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
200 case FcTypeBool:
201 return va.u.b == vb.u.b;
202 case FcTypeMatrix:
203 return FcMatrixEqual (va.u.m, vb.u.m);
204 case FcTypeCharSet:
205 return FcCharSetEqual (va.u.c, vb.u.c);
206 case FcTypeFTFace:
207 return va.u.f == vb.u.f;
208 case FcTypeLangSet:
209 return FcLangSetEqual (va.u.l, vb.u.l);
210 }
211 return FcFalse;
212 }
213
214 static FcChar32
215 FcDoubleHash (double d)
216 {
217 if (d < 0)
218 d = -d;
219 if (d > 0xffffffff)
220 d = 0xffffffff;
221 return (FcChar32) d;
222 }
223
224 FcChar32
225 FcStringHash (const FcChar8 *s)
226 {
227 FcChar8 c;
228 FcChar32 h = 0;
229
230 if (s)
231 while ((c = *s++))
232 h = ((h << 1) | (h >> 31)) ^ c;
233 return h;
234 }
235
236 static FcChar32
237 FcValueHash (const FcValue *v0)
238 {
239 FcValue v = FcValueCanonicalize(v0);
240 switch (v.type) {
241 case FcTypeVoid:
242 return 0;
243 case FcTypeInteger:
244 return (FcChar32) v.u.i;
245 case FcTypeDouble:
246 return FcDoubleHash (v.u.d);
247 case FcTypeString:
248 return FcStringHash (v.u.s);
249 case FcTypeBool:
250 return (FcChar32) v.u.b;
251 case FcTypeMatrix:
252 return (FcDoubleHash (v.u.m->xx) ^
253 FcDoubleHash (v.u.m->xy) ^
254 FcDoubleHash (v.u.m->yx) ^
255 FcDoubleHash (v.u.m->yy));
256 case FcTypeCharSet:
257 return (FcChar32) v.u.c->num;
258 case FcTypeFTFace:
259 return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
260 FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
261 case FcTypeLangSet:
262 return FcLangSetHash (v.u.l);
263 }
264 return FcFalse;
265 }
266
267 static FcBool
268 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
269 {
270 if (FcValueListPtrU(la) == FcValueListPtrU(lb))
271 return FcTrue;
272
273 while (FcValueListPtrU(la) && FcValueListPtrU(lb))
274 {
275 if (!FcValueEqual (FcValueListPtrU(la)->value,
276 FcValueListPtrU(lb)->value))
277 return FcFalse;
278 la = FcValueListPtrU(la)->next;
279 lb = FcValueListPtrU(lb)->next;
280 }
281 if (FcValueListPtrU(la) || FcValueListPtrU(lb))
282 return FcFalse;
283 return FcTrue;
284 }
285
286 static FcChar32
287 FcValueListHash (FcValueListPtr l)
288 {
289 FcChar32 hash = 0;
290
291 while (FcValueListPtrU(l))
292 {
293 hash = ((hash << 1) | (hash >> 31)) ^
294 FcValueHash (&FcValueListPtrU(l)->value);
295 l = FcValueListPtrU(l)->next;
296 }
297 return hash;
298 }
299
300 void
301 FcPatternDestroy (FcPattern *p)
302 {
303 int i;
304
305 if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
306 return;
307
308 if (FcPatternFindFullFname (p))
309 {
310 FcStrFree ((FcChar8 *)FcPatternFindFullFname (p));
311 FcPatternAddFullFname (p, 0);
312 }
313
314 for (i = 0; i < p->num; i++)
315 FcValueListDestroy ((FcPatternEltU(p->elts)+i)->values);
316
317 p->num = 0;
318 if (FcPatternEltU(p->elts) && p->elts.bank == FC_BANK_DYNAMIC)
319 {
320 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
321 free (FcPatternEltU(p->elts));
322 p->elts = FcPatternEltPtrCreateDynamic(0);
323 }
324 p->size = 0;
325 FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
326 free (p);
327 }
328
329 #define FC_VALUE_LIST_HASH_SIZE 257
330 #define FC_PATTERN_HASH_SIZE 67
331
332 typedef struct _FcValueListEnt FcValueListEnt;
333
334 struct _FcValueListEnt {
335 FcValueListEnt *next;
336 FcValueListPtr list;
337 FcChar32 hash, pad;
338 };
339
340 typedef union _FcValueListAlign {
341 FcValueListEnt ent;
342 FcValueList list;
343 } FcValueListAlign;
344
345 static int FcValueListFrozenCount[FcTypeLangSet + 1];
346 static int FcValueListFrozenBytes[FcTypeLangSet + 1];
347 static char FcValueListFrozenName[][8] = {
348 "Void",
349 "Integer",
350 "Double",
351 "String",
352 "Bool",
353 "Matrix",
354 "CharSet",
355 "FTFace",
356 "LangSet"
357 };
358
359 void
360 FcValueListReport (void);
361
362 void
363 FcValueListReport (void)
364 {
365 FcType t;
366
367 printf ("Fc Frozen Values:\n");
368 printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
369 for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
370 printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
371 FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
372 }
373
374 static FcValueListEnt *
375 FcValueListEntCreate (FcValueListPtr h)
376 {
377 FcValueListAlign *ea;
378 FcValueListEnt *e;
379 FcValueListPtr l;
380 FcValueList *new;
381 int n;
382 int size;
383
384 n = 0;
385 for (l = h; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
386 n++;
387 size = sizeof (FcValueListAlign) + n * sizeof (FcValueList);
388 FcValueListFrozenCount[FcValueListPtrU(h)->value.type]++;
389 FcValueListFrozenBytes[FcValueListPtrU(h)->value.type] += size;
390 // this leaks for some reason
391 ea = malloc (sizeof (FcValueListAlign));
392 if (!ea)
393 return 0;
394 new = malloc (n * sizeof (FcValueList));
395 if (!new)
396 return 0;
397 memset(new, 0, n * sizeof (FcValueList));
398 FcMemAlloc (FC_MEM_VALLIST, size);
399 e = &ea->ent;
400 e->list = (FcValueListPtr) FcValueListPtrCreateDynamic(new);
401 for (l = h; FcValueListPtrU(l);
402 l = FcValueListPtrU(l)->next, new++)
403 {
404 if ((FcValueListPtrU(l)->value.type & ~FC_STORAGE_STATIC) == FcTypeString)
405 {
406 new->value.type = FcTypeString;
407 new->value.u.s = FcStrStaticName
408 (fc_value_string(&FcValueListPtrU(l)->value));
409 }
410 else
411 {
412 new->value = FcValueSave (FcValueCanonicalize
413 (&FcValueListPtrU(l)->value));
414 }
415 new->binding = FcValueListPtrU(l)->binding;
416 if (FcValueListPtrU(FcValueListPtrU(l)->next))
417 {
418 new->next = FcValueListPtrCreateDynamic(new + 1);
419 }
420 else
421 {
422 new->next = FcValueListPtrCreateDynamic(0);
423 }
424 }
425 return e;
426 }
427
428 static void
429 FcValueListEntDestroy (FcValueListEnt *e)
430 {
431 FcValueListPtr l;
432
433 FcValueListFrozenCount[FcValueListPtrU(e->list)->value.type]--;
434
435 /* XXX: We should perform these two operations with "size" as
436 computed in FcValueListEntCreate, but we don't have access to
437 that value here. Without this, the FcValueListFrozenBytes
438 values will be wrong as will the FcMemFree counts.
439
440 FcValueListFrozenBytes[e->list->value.type] -= size;
441 FcMemFree (FC_MEM_VALLIST, size);
442 */
443
444 for (l = e->list; FcValueListPtrU(l);
445 l = FcValueListPtrU(l)->next)
446 {
447 if (FcValueListPtrU(l)->value.type != FcTypeString)
448 FcValueDestroy (FcValueListPtrU(l)->value);
449 }
450 /* XXX: Are we being too chummy with the implementation here to
451 free(e) when it was actually the enclosing FcValueListAlign
452 that was allocated? */
453 free (e);
454 }
455
456 static int FcValueListTotal;
457 static int FcValueListUsed;
458
459 static FcValueListEnt *FcValueListHashTable[FC_VALUE_LIST_HASH_SIZE];
460
461 static FcValueListPtr
462 FcValueListFreeze (FcValueListPtr l)
463 {
464 FcChar32 hash = FcValueListHash (l);
465 FcValueListEnt **bucket = &FcValueListHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
466 FcValueListEnt *ent;
467
468 FcValueListTotal++;
469 for (ent = *bucket; ent; ent = ent->next)
470 {
471 if (ent->hash == hash && FcValueListEqual (ent->list, l))
472 return ent->list;
473 }
474
475 ent = FcValueListEntCreate (l);
476 if (!ent)
477 return FcValueListPtrCreateDynamic(0);
478
479 FcValueListUsed++;
480 ent->hash = hash;
481 ent->next = *bucket;
482 *bucket = ent;
483 return ent->list;
484 }
485
486 static void
487 FcValueListThawAll (void)
488 {
489 int i;
490 FcValueListEnt *ent, *next;
491
492 for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
493 {
494 for (ent = FcValueListHashTable[i]; ent; ent = next)
495 {
496 next = ent->next;
497 FcValueListEntDestroy (ent);
498 }
499 FcValueListHashTable[i] = 0;
500 }
501
502 FcValueListTotal = 0;
503 FcValueListUsed = 0;
504 }
505
506 static FcChar32
507 FcPatternBaseHash (FcPattern *b)
508 {
509 FcChar32 hash = b->num;
510 int i;
511
512 for (i = 0; i < b->num; i++)
513 hash = ((hash << 1) | (hash >> 31)) ^
514 (long) (FcValueListPtrU((FcPatternEltU(b->elts)+i)->values));
515 return hash;
516 }
517
518 typedef struct _FcPatternEnt FcPatternEnt;
519
520 struct _FcPatternEnt {
521 FcPatternEnt *next;
522 FcChar32 hash;
523 FcPattern *pattern;
524 };
525
526 static int FcPatternTotal;
527 static int FcPatternUsed;
528
529 static FcPatternEnt *FcPatternHashTable[FC_VALUE_LIST_HASH_SIZE];
530
531 static FcPattern *
532 FcPatternBaseFreeze (FcPattern *b)
533 {
534 FcPattern *ep;
535 FcPatternElt *epp;
536 FcChar32 hash = FcPatternBaseHash (b);
537 FcPatternEnt **bucket = &FcPatternHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
538 FcPatternEnt *ent;
539 int i;
540
541 FcPatternTotal++;
542 for (ent = *bucket; ent; ent = ent->next)
543 {
544 if (ent->hash == hash && b->num == ent->pattern->num)
545 {
546 for (i = 0; i < b->num; i++)
547 {
548 if (FcObjectPtrCompare((FcPatternEltU(b->elts)+i)->object,
549 (FcPatternEltU(ent->pattern->elts)+i)->object) != 0)
550 break;
551 if (FcValueListPtrU((FcPatternEltU(b->elts)+i)->values) !=
552 FcValueListPtrU((FcPatternEltU(ent->pattern->elts)+i)->values))
553 break;
554 }
555 if (i == b->num)
556 return ent->pattern;
557 }
558 }
559
560 /*
561 * Compute size of pattern + elts
562 */
563 ent = malloc (sizeof (FcPatternEnt));
564 if (!ent)
565 return 0;
566
567 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPatternEnt));
568 FcPatternUsed++;
569
570 ep = FcPatternCreate();
571 if (!ep)
572 return 0;
573 ent->pattern = ep;
574 epp = malloc(b->num * sizeof (FcPatternElt));
575 if (!epp)
576 goto bail;
577 ep->elts = FcPatternEltPtrCreateDynamic(epp);
578
579 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
580
581 ep->num = b->num;
582 ep->size = b->num;
583 ep->ref = FC_REF_CONSTANT;
584
585 for (i = 0; i < b->num; i++)
586 {
587 (FcPatternEltU(ep->elts)+i)->values =
588 (FcPatternEltU(b->elts)+i)->values;
589 (FcPatternEltU(ep->elts)+i)->object =
590 (FcPatternEltU(b->elts)+i)->object;
591 }
592
593 if (FcPatternFindElt (b, FC_FILE))
594 FcPatternTransferFullFname (ep, b);
595
596 ent->hash = hash;
597 ent->next = *bucket;
598 *bucket = ent;
599 return ent->pattern;
600 bail:
601 free(ent);
602 FcMemFree (FC_MEM_PATTERN, sizeof (FcPatternEnt));
603 FcPatternUsed--;
604 return 0;
605 }
606
607 static void
608 FcPatternBaseThawAll (void)
609 {
610 int i;
611 FcPatternEnt *ent, *next;
612
613 for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
614 {
615 for (ent = FcPatternHashTable[i]; ent; ent = next)
616 {
617 next = ent->next;
618 free (ent);
619 }
620 FcPatternHashTable[i] = 0;
621 }
622
623 FcPatternTotal = 0;
624 FcPatternUsed = 0;
625 }
626
627 FcPattern *
628 FcPatternFreeze (FcPattern *p)
629 {
630 FcPattern *b, *n = 0;
631 FcPatternElt *e;
632 int i;
633
634 if (p->ref == FC_REF_CONSTANT)
635 return p;
636
637 b = FcPatternCreate();
638 if (!b)
639 return 0;
640
641 b->num = p->num;
642 b->size = b->num;
643 b->ref = 1;
644
645 e = malloc(b->num * sizeof (FcPatternElt));
646 if (!e)
647 return 0;
648 b->elts = FcPatternEltPtrCreateDynamic(e);
649 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
650
651 /*
652 * Freeze object lists
653 */
654 for (i = 0; i < p->num; i++)
655 {
656 (FcPatternEltU(b->elts)+i)->object =
657 (FcPatternEltU(p->elts)+i)->object;
658 (FcPatternEltU(b->elts)+i)->values =
659 FcValueListFreeze((FcPatternEltU(p->elts)+i)->values);
660 if (!FcValueListPtrU((FcPatternEltU(p->elts)+i)->values))
661 goto bail;
662 }
663
664 if (FcPatternFindElt (p, FC_FILE))
665 FcPatternTransferFullFname (b, p);
666
667 /*
668 * Freeze base
669 */
670 n = FcPatternBaseFreeze (b);
671 #ifdef CHATTY
672 if (FcDebug() & FC_DBG_MEMORY)
673 {
674 printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
675 printf ("Patterns: total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
676 }
677 #endif
678 bail:
679 free(FcPatternEltU(b->elts));
680 b->elts = FcPatternEltPtrCreateDynamic(0);
681 FcMemFree (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
682 b->num = -1;
683 #ifdef DEBUG
684 assert (FcPatternEqual (n, p));
685 #endif
686 return n;
687 }
688
689 static int
690 FcPatternPosition (const FcPattern *p, const char *object)
691 {
692 int low, high, mid, c;
693 FcObjectPtr obj;
694
695 obj = FcObjectToPtr(object);
696 low = 0;
697 high = p->num - 1;
698 c = 1;
699 mid = 0;
700 while (low <= high)
701 {
702 mid = (low + high) >> 1;
703 c = FcObjectPtrCompare((FcPatternEltU(p->elts)+mid)->object, obj);
704 if (c == 0)
705 return mid;
706 if (c < 0)
707 low = mid + 1;
708 else
709 high = mid - 1;
710 }
711 if (c < 0)
712 mid++;
713 return -(mid + 1);
714 }
715
716 FcPatternElt *
717 FcPatternFindElt (const FcPattern *p, const char *object)
718 {
719 int i = FcPatternPosition (p, object);
720 if (i < 0)
721 return 0;
722 return FcPatternEltU(p->elts)+i;
723 }
724
725 FcPatternElt *
726 FcPatternInsertElt (FcPattern *p, const char *object)
727 {
728 int i;
729 FcPatternElt *e;
730
731 i = FcPatternPosition (p, object);
732 if (i < 0)
733 {
734 i = -i - 1;
735
736 /* reallocate array */
737 if (p->num + 1 >= p->size)
738 {
739 int s = p->size + 16;
740 if (FcPatternEltU(p->elts))
741 {
742 FcPatternElt *e0 = FcPatternEltU(p->elts);
743 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
744 if (!e) /* maybe it was mmapped */
745 {
746 e = malloc(s * sizeof (FcPatternElt));
747 if (e)
748 memcpy(e, e0, p->num * sizeof (FcPatternElt));
749 }
750 }
751 else
752 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
753 if (!e)
754 return FcFalse;
755 p->elts = FcPatternEltPtrCreateDynamic(e);
756 if (p->size)
757 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
758 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
759 while (p->size < s)
760 {
761 (FcPatternEltU(p->elts)+p->size)->object = 0;
762 (FcPatternEltU(p->elts)+p->size)->values =
763 FcValueListPtrCreateDynamic(0);
764 p->size++;
765 }
766 }
767
768 /* move elts up */
769 memmove (FcPatternEltU(p->elts) + i + 1,
770 FcPatternEltU(p->elts) + i,
771 sizeof (FcPatternElt) *
772 (p->num - i));
773
774 /* bump count */
775 p->num++;
776
777 (FcPatternEltU(p->elts)+i)->object = FcObjectToPtr (object);
778 (FcPatternEltU(p->elts)+i)->values = FcValueListPtrCreateDynamic(0);
779 }
780
781 return FcPatternEltU(p->elts)+i;
782 }
783
784 FcBool
785 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
786 {
787 int i;
788
789 if (pa == pb)
790 return FcTrue;
791
792 if (pa->num != pb->num)
793 return FcFalse;
794 for (i = 0; i < pa->num; i++)
795 {
796 if (FcObjectPtrCompare((FcPatternEltU(pa->elts)+i)->object,
797 (FcPatternEltU(pb->elts)+i)->object) != 0)
798 return FcFalse;
799 if (!FcValueListEqual ((FcPatternEltU(pa->elts)+i)->values,
800 (FcPatternEltU(pb->elts)+i)->values))
801 return FcFalse;
802 }
803 return FcTrue;
804 }
805
806 FcChar32
807 FcPatternHash (const FcPattern *p)
808 {
809 int i;
810 FcChar32 h = 0;
811
812 for (i = 0; i < p->num; i++)
813 {
814 h = (((h << 1) | (h >> 31)) ^
815 FcStringHash ((FcChar8 *)FcObjectPtrU ((FcPatternEltU(p->elts)+i)->object)) ^
816 FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
817 }
818 return h;
819 }
820
821 FcBool
822 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
823 {
824 FcPatternElt *ea, *eb;
825 int i;
826
827 for (i = 0; i < os->nobject; i++)
828 {
829 ea = FcPatternFindElt (pai, os->objects[i]);
830 eb = FcPatternFindElt (pbi, os->objects[i]);
831 if (ea)
832 {
833 if (!eb)
834 return FcFalse;
835 if (!FcValueListEqual (ea->values, eb->values))
836 return FcFalse;
837 }
838 else
839 {
840 if (eb)
841 return FcFalse;
842 }
843 }
844 return FcTrue;
845 }
846
847 FcBool
848 FcPatternAddWithBinding (FcPattern *p,
849 const char *object,
850 FcValue value,
851 FcValueBinding binding,
852 FcBool append)
853 {
854 FcPatternElt *e;
855 FcValueListPtr new, *prev;
856 FcValueList *newp;
857 FcObjectPtr objectPtr;
858
859 if (p->ref == FC_REF_CONSTANT)
860 goto bail0;
861
862 newp = malloc (sizeof (FcValueList));
863 if (!newp)
864 goto bail0;
865
866 memset(newp, 0, sizeof (FcValueList));
867 new = FcValueListPtrCreateDynamic(newp);
868 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
869 /* dup string */
870 value = FcValueSave (value);
871 if (value.type == FcTypeVoid)
872 goto bail1;
873
874 /* quick and dirty hack to enable FcCompareFamily/FcCompareString
875 * speedup: only allow strings to be added under the FC_FAMILY,
876 * FC_FOUNDRY, FC_STYLE, FC_RASTERIZER keys.
877 * and charsets under FC_CHARSET key.
878 * This is slightly semantically different from the old behaviour,
879 * but fonts shouldn't be getting non-strings here anyway.
880 * a better hack would use FcBaseObjectTypes to check all objects. */
881 objectPtr = FcObjectToPtr(object);
882 if ((objectPtr == FcObjectToPtr(FC_FAMILY)
883 || objectPtr == FcObjectToPtr(FC_FOUNDRY)
884 || objectPtr == FcObjectToPtr(FC_STYLE)
885 || objectPtr == FcObjectToPtr(FC_RASTERIZER))
886 && value.type != FcTypeString)
887 goto bail1;
888 if (objectPtr == FcObjectToPtr(FC_CHARSET)
889 && value.type != FcTypeCharSet)
890 goto bail1;
891
892 FcValueListPtrU(new)->value = value;
893 FcValueListPtrU(new)->binding = binding;
894 FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
895
896 e = FcPatternInsertElt (p, object);
897 if (!e)
898 goto bail2;
899
900 if (append)
901 {
902 for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
903 ;
904 *prev = new;
905 }
906 else
907 {
908 FcValueListPtrU(new)->next = e->values;
909 e->values = new;
910 }
911
912 return FcTrue;
913
914 bail2:
915 switch (value.type) {
916 case FcTypeString:
917 FcStrFree ((FcChar8 *) value.u.s);
918 break;
919 case FcTypeMatrix:
920 FcMatrixFree ((FcMatrix *) value.u.m);
921 break;
922 case FcTypeCharSet:
923 FcCharSetDestroy ((FcCharSet *) value.u.c);
924 break;
925 case FcTypeLangSet:
926 FcLangSetDestroy ((FcLangSet *) value.u.l);
927 break;
928 default:
929 break;
930 }
931 bail1:
932 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
933 free (FcValueListPtrU(new));
934 bail0:
935 return FcFalse;
936 }
937
938 FcBool
939 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
940 {
941 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
942 }
943
944 FcBool
945 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
946 {
947 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
948 }
949
950 FcBool
951 FcPatternDel (FcPattern *p, const char *object)
952 {
953 FcPatternElt *e;
954
955 e = FcPatternFindElt (p, object);
956 if (!e)
957 return FcFalse;
958
959 /* destroy value */
960 FcValueListDestroy (e->values);
961
962 /* shuffle existing ones down */
963 memmove (e, e+1,
964 (FcPatternEltU(p->elts) + p->num - (e + 1)) *
965 sizeof (FcPatternElt));
966 p->num--;
967 (FcPatternEltU(p->elts)+p->num)->object = 0;
968 (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
969 return FcTrue;
970 }
971
972 FcBool
973 FcPatternRemove (FcPattern *p, const char *object, int id)
974 {
975 FcPatternElt *e;
976 FcValueListPtr *prev, l;
977
978 e = FcPatternFindElt (p, object);
979 if (!e)
980 return FcFalse;
981 for (prev = &e->values;
982 FcValueListPtrU(l = *prev);
983 prev = &FcValueListPtrU(l)->next)
984 {
985 if (!id)
986 {
987 *prev = FcValueListPtrU(l)->next;
988 FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
989 FcValueListDestroy (l);
990 if (!FcValueListPtrU(e->values))
991 FcPatternDel (p, object);
992 return FcTrue;
993 }
994 id--;
995 }
996 return FcFalse;
997 }
998
999 FcBool
1000 FcPatternAddInteger (FcPattern *p, const char *object, int i)
1001 {
1002 FcValue v;
1003
1004 v.type = FcTypeInteger;
1005 v.u.i = i;
1006 return FcPatternAdd (p, object, v, FcTrue);
1007 }
1008
1009 FcBool
1010 FcPatternAddDouble (FcPattern *p, const char *object, double d)
1011 {
1012 FcValue v;
1013
1014 v.type = FcTypeDouble;
1015 v.u.d = d;
1016 return FcPatternAdd (p, object, v, FcTrue);
1017 }
1018
1019
1020 FcBool
1021 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
1022 {
1023 FcValue v;
1024
1025 v.type = FcTypeString;
1026 v.u.s = FcStrStaticName(s);
1027 return FcPatternAdd (p, object, v, FcTrue);
1028 }
1029
1030 FcBool
1031 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
1032 {
1033 FcValue v;
1034
1035 v.type = FcTypeMatrix;
1036 v.u.m = s;
1037 return FcPatternAdd (p, object, v, FcTrue);
1038 }
1039
1040
1041 FcBool
1042 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
1043 {
1044 FcValue v;
1045
1046 v.type = FcTypeBool;
1047 v.u.b = b;
1048 return FcPatternAdd (p, object, v, FcTrue);
1049 }
1050
1051 FcBool
1052 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
1053 {
1054 FcValue v;
1055
1056 v.type = FcTypeCharSet;
1057 v.u.c = (FcCharSet *)c;
1058 return FcPatternAdd (p, object, v, FcTrue);
1059 }
1060
1061 FcBool
1062 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
1063 {
1064 FcValue v;
1065
1066 v.type = FcTypeFTFace;
1067 v.u.f = (void *) f;
1068 return FcPatternAdd (p, object, v, FcTrue);
1069 }
1070
1071 FcBool
1072 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1073 {
1074 FcValue v;
1075
1076 v.type = FcTypeLangSet;
1077 v.u.l = (FcLangSet *)ls;
1078 return FcPatternAdd (p, object, v, FcTrue);
1079 }
1080
1081 FcResult
1082 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
1083 {
1084 FcPatternElt *e;
1085 FcValueListPtr l;
1086
1087 e = FcPatternFindElt (p, object);
1088 if (!e)
1089 return FcResultNoMatch;
1090 for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
1091 {
1092 if (!id)
1093 {
1094 *v = FcValueCanonicalize(&FcValueListPtrU(l)->value);
1095 return FcResultMatch;
1096 }
1097 id--;
1098 }
1099 return FcResultNoId;
1100 }
1101
1102 FcResult
1103 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
1104 {
1105 FcValue v;
1106 FcResult r;
1107
1108 r = FcPatternGet (p, object, id, &v);
1109 if (r != FcResultMatch)
1110 return r;
1111 switch (v.type) {
1112 case FcTypeDouble:
1113 *i = (int) v.u.d;
1114 break;
1115 case FcTypeInteger:
1116 *i = v.u.i;
1117 break;
1118 default:
1119 return FcResultTypeMismatch;
1120 }
1121 return FcResultMatch;
1122 }
1123
1124 FcResult
1125 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
1126 {
1127 FcValue v;
1128 FcResult r;
1129
1130 r = FcPatternGet (p, object, id, &v);
1131 if (r != FcResultMatch)
1132 return r;
1133 switch (v.type) {
1134 case FcTypeDouble:
1135 *d = v.u.d;
1136 break;
1137 case FcTypeInteger:
1138 *d = (double) v.u.i;
1139 break;
1140 default:
1141 return FcResultTypeMismatch;
1142 }
1143 return FcResultMatch;
1144 }
1145
1146 FcResult
1147 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1148 {
1149 FcValue v;
1150 FcResult r;
1151
1152 r = FcPatternGet (p, object, id, &v);
1153 if (r != FcResultMatch)
1154 return r;
1155 if (v.type != FcTypeString)
1156 return FcResultTypeMismatch;
1157
1158 if (FcObjectToPtr(object) == FcObjectToPtr(FC_FILE))
1159 {
1160 const char *fn, *fpath;
1161 FcChar8 *fname;
1162 int size;
1163
1164 fn = FcPatternFindFullFname(p);
1165 if (fn)
1166 {
1167 *s = (FcChar8 *) fn;
1168 return FcResultMatch;
1169 }
1170
1171 if (!p->bank)
1172 {
1173 *s = (FcChar8 *) v.u.s;
1174 return FcResultMatch;
1175 }
1176
1177 fpath = FcCacheFindBankDir (p->bank);
1178 size = strlen((char*)fpath) + 1 + strlen ((char *)v.u.s) + 1;
1179 fname = malloc (size);
1180 if (!fname)
1181 return FcResultOutOfMemory;
1182
1183 FcMemAlloc (FC_MEM_STRING, size);
1184 strcpy ((char *)fname, (char *)fpath);
1185 strcat ((char *)fname, "/");
1186 strcat ((char *)fname, (char *)v.u.s);
1187
1188 FcPatternAddFullFname (p, (const char *)fname);
1189 *s = (FcChar8 *)fname;
1190 return FcResultMatch;
1191 }
1192
1193 *s = (FcChar8 *) v.u.s;
1194 return FcResultMatch;
1195 }
1196
1197 FcResult
1198 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1199 {
1200 FcValue v;
1201 FcResult r;
1202
1203 r = FcPatternGet (p, object, id, &v);
1204 if (r != FcResultMatch)
1205 return r;
1206 if (v.type != FcTypeMatrix)
1207 return FcResultTypeMismatch;
1208 *m = (FcMatrix *)v.u.m;
1209 return FcResultMatch;
1210 }
1211
1212
1213 FcResult
1214 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1215 {
1216 FcValue v;
1217 FcResult r;
1218
1219 r = FcPatternGet (p, object, id, &v);
1220 if (r != FcResultMatch)
1221 return r;
1222 if (v.type != FcTypeBool)
1223 return FcResultTypeMismatch;
1224 *b = v.u.b;
1225 return FcResultMatch;
1226 }
1227
1228 FcResult
1229 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1230 {
1231 FcValue v;
1232 FcResult r;
1233
1234 r = FcPatternGet (p, object, id, &v);
1235 if (r != FcResultMatch)
1236 return r;
1237 if (v.type != FcTypeCharSet)
1238 return FcResultTypeMismatch;
1239 *c = (FcCharSet *)v.u.c;
1240 return FcResultMatch;
1241 }
1242
1243 FcResult
1244 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1245 {
1246 FcValue v;
1247 FcResult r;
1248
1249 r = FcPatternGet (p, object, id, &v);
1250 if (r != FcResultMatch)
1251 return r;
1252 if (v.type != FcTypeFTFace)
1253 return FcResultTypeMismatch;
1254 *f = (FT_Face) v.u.f;
1255 return FcResultMatch;
1256 }
1257
1258 FcResult
1259 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1260 {
1261 FcValue v;
1262 FcResult r;
1263
1264 r = FcPatternGet (p, object, id, &v);
1265 if (r != FcResultMatch)
1266 return r;
1267 if (v.type != FcTypeLangSet)
1268 return FcResultTypeMismatch;
1269 *ls = (FcLangSet *)v.u.l;
1270 return FcResultMatch;
1271 }
1272
1273 FcPattern *
1274 FcPatternDuplicate (const FcPattern *orig)
1275 {
1276 FcPattern *new;
1277 FcPatternElt *e;
1278 int i;
1279 FcValueListPtr l;
1280
1281 new = FcPatternCreate ();
1282 if (!new)
1283 goto bail0;
1284
1285 e = FcPatternEltU(orig->elts);
1286
1287 for (i = 0; i < orig->num; i++)
1288 {
1289 for (l = (e + i)->values;
1290 FcValueListPtrU(l);
1291 l = FcValueListPtrU(l)->next)
1292 if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object),
1293 FcValueCanonicalize(&FcValueListPtrU(l)->value),
1294 FcTrue))
1295 goto bail1;
1296 }
1297 FcPatternTransferFullFname (new, orig);
1298
1299 return new;
1300
1301 bail1:
1302 FcPatternDestroy (new);
1303 bail0:
1304 return 0;
1305 }
1306
1307 void
1308 FcPatternReference (FcPattern *p)
1309 {
1310 if (p->ref != FC_REF_CONSTANT)
1311 p->ref++;
1312 }
1313
1314 FcPattern *
1315 FcPatternVaBuild (FcPattern *orig, va_list va)
1316 {
1317 FcPattern *ret;
1318
1319 FcPatternVapBuild (ret, orig, va);
1320 return ret;
1321 }
1322
1323 FcPattern *
1324 FcPatternBuild (FcPattern *orig, ...)
1325 {
1326 va_list va;
1327
1328 va_start (va, orig);
1329 FcPatternVapBuild (orig, orig, va);
1330 va_end (va);
1331 return orig;
1332 }
1333
1334 /*
1335 * Add all of the elements in 's' to 'p'
1336 */
1337 FcBool
1338 FcPatternAppend (FcPattern *p, FcPattern *s)
1339 {
1340 int i;
1341 FcPatternElt *e;
1342 FcValueListPtr v;
1343
1344 for (i = 0; i < s->num; i++)
1345 {
1346 e = FcPatternEltU(s->elts)+i;
1347 for (v = e->values; FcValueListPtrU(v);
1348 v = FcValueListPtrU(v)->next)
1349 {
1350 if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
1351 FcValueCanonicalize(&FcValueListPtrU(v)->value),
1352 FcValueListPtrU(v)->binding, FcTrue))
1353 return FcFalse;
1354 }
1355 }
1356 return FcTrue;
1357 }
1358
1359 #define OBJECT_HASH_SIZE 31
1360 static struct objectBucket {
1361 struct objectBucket *next;
1362 FcChar32 hash;
1363 } *FcObjectBuckets[OBJECT_HASH_SIZE];
1364
1365 const FcChar8 *
1366 FcStrStaticName (const FcChar8 *name)
1367 {
1368 FcChar32 hash = FcStringHash (name);
1369 struct objectBucket **p;
1370 struct objectBucket *b;
1371 int size;
1372
1373 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1374 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1375 return (FcChar8 *) (b + 1);
1376 size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
1377 b = malloc (size + sizeof (int));
1378 /* workaround glibc bug which reads strlen in groups of 4 */
1379 FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
1380 if (!b)
1381 return NULL;
1382 b->next = 0;
1383 b->hash = hash;
1384 strcpy ((char *) (b + 1), (char *)name);
1385 *p = b;
1386 return (FcChar8 *) (b + 1);
1387 }
1388
1389 static void
1390 FcStrStaticNameFini (void)
1391 {
1392 int i, size;
1393 struct objectBucket *b, *next;
1394 char *name;
1395
1396 for (i = 0; i < OBJECT_HASH_SIZE; i++)
1397 {
1398 for (b = FcObjectBuckets[i]; b; b = next)
1399 {
1400 next = b->next;
1401 name = (char *) (b + 1);
1402 size = sizeof (struct objectBucket) + strlen (name) + 1;
1403 FcMemFree (FC_MEM_STATICSTR, size);
1404 free (b);
1405 }
1406 FcObjectBuckets[i] = 0;
1407 }
1408 }
1409
1410 void
1411 FcPatternFini (void)
1412 {
1413 FcPatternBaseThawAll ();
1414 FcValueListThawAll ();
1415 FcStrStaticNameFini ();
1416 FcObjectStaticNameFini ();
1417 }
1418
1419 static FcPatternEltPtr
1420 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1421 {
1422 FcPatternEltPtr new;
1423 new.bank = FC_BANK_DYNAMIC;
1424 new.u.dyn = e;
1425 return new;
1426 }
1427
1428 static FcPatternEltPtr
1429 FcPatternEltPtrCreateStatic (int bank, int i)
1430 {
1431 FcPatternEltPtr new;
1432 new.bank = bank;
1433 new.u.stat = i;
1434 return new;
1435 }
1436
1437 static void
1438 FcStrNewBank (void);
1439 static int
1440 FcStrNeededBytes (const FcChar8 * s);
1441 static int
1442 FcStrNeededBytesAlign (void);
1443 static void *
1444 FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
1445 static const FcChar8 *
1446 FcStrSerialize (int bank, const FcChar8 * s);
1447 static void *
1448 FcStrUnserialize (FcCache * metadata, void *block_ptr);
1449
1450 static void
1451 FcValueListNewBank (void);
1452 static int
1453 FcValueListNeededBytes (FcValueList * vl);
1454 static int
1455 FcValueListNeededBytesAlign (void);
1456 static void *
1457 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
1458 static FcValueListPtr
1459 FcValueListSerialize(int bank, FcValueList *pi);
1460 static void *
1461 FcValueListUnserialize (FcCache * metadata, void *block_ptr);
1462
1463
1464 void
1465 FcPatternNewBank (void)
1466 {
1467 fcpattern_count = 0;
1468 fcpatternelt_count = 0;
1469
1470 FcStrNewBank();
1471 FcValueListNewBank();
1472 }
1473
1474 int
1475 FcPatternNeededBytes (FcPattern * p)
1476 {
1477 int i, cum = 0, c;
1478
1479 fcpattern_count++;
1480 fcpatternelt_count += p->num;
1481
1482 for (i = 0; i < p->num; i++)
1483 {
1484 c = FcValueListNeededBytes (FcValueListPtrU
1485 (((FcPatternEltU(p->elts)+i)->values)));
1486 if (c < 0)
1487 return c;
1488 cum += c;
1489 }
1490
1491 return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
1492 }
1493
1494 int
1495 FcPatternNeededBytesAlign (void)
1496 {
1497 return __alignof__ (FcPattern) + __alignof__ (FcPatternElt) +
1498 FcValueListNeededBytesAlign ();
1499 }
1500
1501 static FcBool
1502 FcPatternEnsureBank (int bi)
1503 {
1504 FcPattern **pp;
1505 FcPatternElt **ep;
1506 int i;
1507
1508 if (!_fcPatterns || fcpattern_bank_count <= bi)
1509 {
1510 int new_count = bi + 4;
1511 pp = realloc (_fcPatterns, sizeof (FcPattern *) * new_count);
1512 if (!pp)
1513 return 0;
1514
1515 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern *) * new_count);
1516 _fcPatterns = pp;
1517
1518 ep = realloc (_fcPatternElts, sizeof (FcPatternElt *) * new_count);
1519 if (!ep)
1520 return 0;
1521
1522 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt *) * new_count);
1523 _fcPatternElts = ep;
1524
1525 for (i = fcpattern_bank_count; i < new_count; i++)
1526 {
1527 _fcPatterns[i] = 0;
1528 _fcPatternElts[i] = 0;
1529 }
1530
1531 fcpattern_bank_count = new_count;
1532 }
1533
1534 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
1535 return FcTrue;
1536 }
1537
1538 void *
1539 FcPatternDistributeBytes (FcCache * metadata, void * block_ptr)
1540 {
1541 int bi = FcCacheBankToIndex(metadata->bank);
1542
1543 if (!FcPatternEnsureBank(bi))
1544 return 0;
1545
1546 fcpattern_ptr = 0;
1547 block_ptr = ALIGN(block_ptr, FcPattern);
1548 _fcPatterns[bi] = (FcPattern *)block_ptr;
1549 block_ptr = (void *)((char *)block_ptr +
1550 (sizeof (FcPattern) * fcpattern_count));
1551
1552 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
1553 fcpatternelt_ptr = 0;
1554 block_ptr = ALIGN(block_ptr, FcPatternElt);
1555 _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
1556 block_ptr = (void *)((char *)block_ptr +
1557 (sizeof (FcPatternElt) * fcpatternelt_count));
1558
1559 metadata->pattern_count = fcpattern_count;
1560 metadata->patternelt_count = fcpatternelt_count;
1561
1562 block_ptr = FcStrDistributeBytes (metadata, block_ptr);
1563 block_ptr = FcValueListDistributeBytes (metadata, block_ptr);
1564 return block_ptr;
1565 }
1566
1567 FcPattern *
1568 FcPatternSerialize (int bank, FcPattern *old)
1569 {
1570 FcPattern *p;
1571 FcPatternElt *e, *nep;
1572 FcValueList * nv;
1573 FcValueListPtr v, nv_head, nvp;
1574 int i, elts, bi = FcCacheBankToIndex(bank);
1575
1576 p = &_fcPatterns[bi][fcpattern_ptr++];
1577 p->bank = bank;
1578 elts = fcpatternelt_ptr;
1579 nep = &_fcPatternElts[bi][elts];
1580 if (!nep)
1581 return FcFalse;
1582
1583 fcpatternelt_ptr += old->num;
1584
1585 for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++)
1586 {
1587 v = e->values;
1588 nvp = nv_head = FcValueListSerialize(bank, FcValueListPtrU(v));
1589 if (!FcValueListPtrU(nv_head))
1590 return 0;
1591 nv = FcValueListPtrU(nvp);
1592
1593 for (;
1594 FcValueListPtrU(v);
1595 v = FcValueListPtrU(v)->next,
1596 nv = FcValueListPtrU(nv->next))
1597 {
1598
1599 if (FcValueListPtrU(FcValueListPtrU(v)->next))
1600 {
1601 nvp = FcValueListSerialize
1602 (bank, FcValueListPtrU(FcValueListPtrU(v)->next));
1603 nv->next = nvp;
1604 }
1605 }
1606
1607 nep[i].values = nv_head;
1608 nep[i].object = e->object;
1609 }
1610
1611 p->elts = old->elts;
1612 p->elts = FcPatternEltPtrCreateStatic(bank, elts);
1613 p->size = old->num;
1614 p->num = old->num;
1615 p->ref = FC_REF_CONSTANT;
1616 return p;
1617 }
1618
1619 void *
1620 FcPatternUnserialize (FcCache * metadata, void *block_ptr)
1621 {
1622 int bi = FcCacheBankToIndex(metadata->bank);
1623 if (!FcPatternEnsureBank(bi))
1624 return FcFalse;
1625
1626 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata->pattern_count);
1627 block_ptr = ALIGN(block_ptr, FcPattern);
1628 _fcPatterns[bi] = (FcPattern *)block_ptr;
1629 block_ptr = (void *)((char *)block_ptr +
1630 (sizeof (FcPattern) * metadata->pattern_count));
1631
1632 FcMemAlloc (FC_MEM_PATELT,
1633 sizeof (FcPatternElt) * metadata->patternelt_count);
1634 block_ptr = ALIGN(block_ptr, FcPatternElt);
1635 _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
1636 block_ptr = (void *)((char *)block_ptr +
1637 (sizeof (FcPatternElt) * metadata->patternelt_count));
1638
1639 block_ptr = FcStrUnserialize (metadata, block_ptr);
1640 block_ptr = FcValueListUnserialize (metadata, block_ptr);
1641
1642 return block_ptr;
1643 }
1644
1645 static void
1646 FcValueListNewBank (void)
1647 {
1648 fcvaluelist_count = 0;
1649
1650 FcCharSetNewBank();
1651 FcLangSetNewBank();
1652 }
1653
1654 static int
1655 FcValueListNeededBytes (FcValueList *p)
1656 {
1657 FcValueList *vl;
1658 int cum = 0;
1659
1660 for (vl = p;
1661 vl;
1662 vl = FcValueListPtrU(vl->next))
1663 {
1664 FcValue v = FcValueCanonicalize(&vl->value); // unserialize just in case
1665
1666 switch (v.type)
1667 {
1668 case FcTypeCharSet:
1669 cum += FcCharSetNeededBytes(v.u.c);
1670 break;
1671 case FcTypeLangSet:
1672 cum += FcLangSetNeededBytes(v.u.l);
1673 break;
1674 case FcTypeString:
1675 cum += FcStrNeededBytes(v.u.s);
1676 default:
1677 break;
1678 }
1679 fcvaluelist_count++;
1680 cum += sizeof (FcValueList);
1681 }
1682
1683 return cum;
1684 }
1685
1686 static int
1687 FcValueListNeededBytesAlign (void)
1688 {
1689 return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() +
1690 FcStrNeededBytesAlign() + __alignof__ (FcValueList);
1691 }
1692
1693 static FcBool
1694 FcValueListEnsureBank (int bi)
1695 {
1696 FcValueList **pvl;
1697
1698 if (!_fcValueLists || fcvaluelist_bank_count <= bi)
1699 {
1700 int new_count = bi + 2, i;
1701
1702 pvl = realloc (_fcValueLists, sizeof (FcValueList *) * new_count);
1703 if (!pvl)
1704 return FcFalse;
1705
1706 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList *) * new_count);
1707
1708 _fcValueLists = pvl;
1709 for (i = fcvaluelist_bank_count; i < new_count; i++)
1710 _fcValueLists[i] = 0;
1711
1712 fcvaluelist_bank_count = new_count;
1713 }
1714 return FcTrue;
1715 }
1716
1717 static void *
1718 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
1719 {
1720 int bi = FcCacheBankToIndex(metadata->bank);
1721
1722 if (!FcValueListEnsureBank(bi))
1723 return 0;
1724
1725 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1726 fcvaluelist_ptr = 0;
1727 block_ptr = ALIGN(block_ptr, FcValueList);
1728 _fcValueLists[bi] = (FcValueList *)block_ptr;
1729 block_ptr = (void *)((char *)block_ptr +
1730 (sizeof (FcValueList) * fcvaluelist_count));
1731 metadata->valuelist_count = fcvaluelist_count;
1732
1733 block_ptr = FcCharSetDistributeBytes(metadata, block_ptr);
1734 block_ptr = FcLangSetDistributeBytes(metadata, block_ptr);
1735
1736 return block_ptr;
1737 }
1738
1739 static FcValueListPtr
1740 FcValueListSerialize(int bank, FcValueList *pi)
1741 {
1742 FcValueListPtr new;
1743 FcValue * v;
1744 int bi = FcCacheBankToIndex(bank);
1745
1746 if (!pi)
1747 {
1748 new.bank = FC_BANK_DYNAMIC;
1749 new.u.dyn = 0;
1750 return new;
1751 }
1752
1753 _fcValueLists[bi][fcvaluelist_ptr] = *pi;
1754 new.bank = bank;
1755 new.u.stat = fcvaluelist_ptr++;
1756 _fcValueLists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
1757 v = &_fcValueLists[bi][new.u.stat].value;
1758 switch (v->type)
1759 {
1760 case FcTypeString:
1761 if (v->u.s)
1762 {
1763 const FcChar8 * s = FcStrSerialize(bank, v->u.s);
1764 if (!s)
1765 return FcValueListPtrCreateDynamic(pi);
1766 v->u.s_off = s - (const FcChar8 *)v;
1767 v->type |= FC_STORAGE_STATIC;
1768 }
1769 break;
1770 case FcTypeMatrix:
1771 break;
1772 case FcTypeCharSet:
1773 if (v->u.c)
1774 {
1775 FcCharSet * c = FcCharSetSerialize(bank, (FcCharSet *)v->u.c);
1776 if (!c)
1777 return FcValueListPtrCreateDynamic(pi);
1778 v->u.c_off = (char *)c - (char *)v;
1779 v->type |= FC_STORAGE_STATIC;
1780 }
1781 break;
1782 case FcTypeLangSet:
1783 if (v->u.l)
1784 {
1785 FcLangSet * l = FcLangSetSerialize(bank, (FcLangSet *)v->u.l);
1786 if (!l)
1787 return FcValueListPtrCreateDynamic(pi);
1788 v->u.l_off = (char *)l - (char *)v;
1789 v->type |= FC_STORAGE_STATIC;
1790 }
1791 break;
1792 default:
1793 break;
1794 }
1795 return new;
1796 }
1797
1798 static void *
1799 FcValueListUnserialize (FcCache * metadata, void *block_ptr)
1800 {
1801 int bi = FcCacheBankToIndex(metadata->bank);
1802
1803 if (!FcValueListEnsureBank(bi))
1804 return 0;
1805
1806 FcMemAlloc (FC_MEM_VALLIST,
1807 sizeof (FcValueList) * metadata->valuelist_count);
1808 block_ptr = ALIGN(block_ptr, FcValueList);
1809 _fcValueLists[bi] = (FcValueList *)block_ptr;
1810 block_ptr = (void *)((char *)block_ptr +
1811 (sizeof (FcValueList) * metadata->valuelist_count));
1812
1813 block_ptr = FcCharSetUnserialize(metadata, block_ptr);
1814 block_ptr = FcLangSetUnserialize(metadata, block_ptr);
1815
1816 return block_ptr;
1817 }
1818
1819 FcValueListPtr
1820 FcValueListPtrCreateDynamic(FcValueList * p)
1821 {
1822 FcValueListPtr r;
1823
1824 r.bank = FC_BANK_DYNAMIC;
1825 r.u.dyn = p;
1826 return r;
1827 }
1828
1829 static FcChar8 ** static_strs;
1830 static int static_str_bank_count = 0, fcstr_ptr, fcstr_count;
1831
1832 static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE];
1833
1834 static void
1835 FcStrNewBank (void)
1836 {
1837 int i, size;
1838 struct objectBucket *b, *next;
1839 char *name;
1840
1841 for (i = 0; i < OBJECT_HASH_SIZE; i++)
1842 {
1843 for (b = FcStrBuckets[i]; b; b = next)
1844 {
1845 next = b->next;
1846 name = (char *) (b + 1);
1847 size = sizeof (struct objectBucket) + strlen (name) + 1;
1848 FcMemFree (FC_MEM_STATICSTR, size);
1849 free (b);
1850 }
1851 FcStrBuckets[i] = 0;
1852 }
1853
1854 fcstr_count = 0;
1855 }
1856
1857 static int
1858 FcStrNeededBytes (const FcChar8 * s)
1859 {
1860 FcChar32 hash = FcStringHash ((const FcChar8 *) s);
1861 struct objectBucket **p;
1862 struct objectBucket *b;
1863 int size;
1864
1865 for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1866 if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1867 return 0;
1868 size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *);
1869 b = malloc (size);
1870 FcMemAlloc (FC_MEM_STATICSTR, size);
1871 if (!b)
1872 return -1;
1873 b->next = 0;
1874 b->hash = hash;
1875 strcpy ((char *) (b + 1), (char *)s);
1876
1877 /* Yes, the following line is convoluted. However, it is
1878 * incorrect to replace the with a memset, because the C
1879 * specification doesn't guarantee that the null pointer is
1880 * the same as the zero bit pattern. */
1881 *(char **)((char *) (b + 1) + strlen((char *)s) + 1) = 0;
1882 *p = b;
1883
1884 fcstr_count += strlen((char *)s) + 1;
1885 return strlen((char *)s) + 1;
1886 }
1887
1888 static int
1889 FcStrNeededBytesAlign (void)
1890 {
1891 return __alignof__ (char);
1892 }
1893
1894 static FcBool
1895 FcStrEnsureBank (int bi)
1896 {
1897 FcChar8 ** ss;
1898
1899 if (!static_strs || static_str_bank_count <= bi)
1900 {
1901 int new_count = bi + 4, i;
1902 ss = realloc (static_strs, sizeof (const char *) * new_count);
1903 if (!ss)
1904 return FcFalse;
1905
1906 FcMemAlloc (FC_MEM_STRING, sizeof (const char *) * (new_count-static_str_bank_count));
1907 static_strs = ss;
1908
1909 for (i = static_str_bank_count; i < new_count; i++)
1910 static_strs[i] = 0;
1911 static_str_bank_count = new_count;
1912 }
1913 return FcTrue;
1914 }
1915
1916 static void *
1917 FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
1918 {
1919 int bi = FcCacheBankToIndex(metadata->bank);
1920 if (!FcStrEnsureBank(bi))
1921 return 0;
1922
1923 FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
1924 block_ptr = ALIGN (block_ptr, FcChar8);
1925 static_strs[bi] = (FcChar8 *)block_ptr;
1926 block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
1927 metadata->str_count = fcstr_count;
1928 fcstr_ptr = 0;
1929
1930 return block_ptr;
1931 }
1932
1933 static const FcChar8 *
1934 FcStrSerialize (int bank, const FcChar8 * s)
1935 {
1936 FcChar32 hash = FcStringHash ((const FcChar8 *) s);
1937 struct objectBucket **p;
1938 struct objectBucket *b;
1939 int bi = FcCacheBankToIndex(bank);
1940
1941 for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1942 if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1943 {
1944 FcChar8 * t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
1945 if (!t)
1946 {
1947 strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
1948 *(FcChar8 **)((FcChar8 *) (b + 1) + strlen((char *)s) + 1) = (static_strs[bi] + fcstr_ptr);
1949 fcstr_ptr += strlen((char *)s) + 1;
1950 t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
1951 }
1952 return t;
1953 }
1954 return 0;
1955 }
1956
1957 static void *
1958 FcStrUnserialize (FcCache * metadata, void *block_ptr)
1959 {
1960 int bi = FcCacheBankToIndex(metadata->bank);
1961 if (!FcStrEnsureBank(bi))
1962 return 0;
1963
1964 FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata->str_count);
1965 block_ptr = ALIGN (block_ptr, FcChar8);
1966 static_strs[bi] = (FcChar8 *)block_ptr;
1967 block_ptr = (void *)((char *)block_ptr +
1968 (sizeof (char) * metadata->str_count));
1969
1970 return block_ptr;
1971 }
1972
1973 /* we don't store these in the FcPattern itself because
1974 * we don't want to serialize the directory names */
1975
1976 /* I suppose this should be cleaned, too... */
1977 typedef struct _FcPatternDirMapping {
1978 const FcPattern *p;
1979 const char *fname;
1980 } FcPatternDirMapping;
1981
1982 #define PATTERNDIR_HASH_SIZE 31
1983 static struct patternDirBucket {
1984 struct patternDirBucket *next;
1985 FcPatternDirMapping m;
1986 } FcPatternDirBuckets[PATTERNDIR_HASH_SIZE];
1987
1988 void
1989 FcPatternAddFullFname (const FcPattern *p, const char *fname)
1990 {
1991 struct patternDirBucket *pb;
1992
1993 /* N.B. FcPatternHash fails, since it's contents-based, not
1994 * address-based, and we're in the process of mutating the FcPattern. */
1995 for (pb = &FcPatternDirBuckets
1996 [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
1997 pb->m.p != p && pb->next;
1998 pb = pb->next)
1999 ;
2000
2001 if (pb->m.p == p)
2002 {
2003 pb->m.fname = fname;
2004 return;
2005 }
2006
2007 pb->next = malloc (sizeof (struct patternDirBucket));
2008 if (!pb->next)
2009 return;
2010 FcMemAlloc (FC_MEM_CACHE, sizeof (struct patternDirBucket));
2011
2012 pb->next->next = 0;
2013 pb->next->m.p = p;
2014 pb->next->m.fname = fname;
2015 }
2016
2017 const char *
2018 FcPatternFindFullFname (const FcPattern *p)
2019 {
2020 struct patternDirBucket *pb;
2021
2022 for (pb = &FcPatternDirBuckets
2023 [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
2024 pb; pb = pb->next)
2025 if (pb->m.p == p)
2026 return pb->m.fname;
2027
2028 return 0;
2029 }
2030
2031 void
2032 FcPatternTransferFullFname (const FcPattern *new, const FcPattern *orig)
2033 {
2034 FcChar8 * s;
2035 FcPatternGetString (orig, FC_FILE, 0, &s);
2036 FcPatternAddFullFname (new,
2037 (char *)FcStrCopy
2038 ((FcChar8 *)FcPatternFindFullFname(orig)));
2039 }