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