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