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