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