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