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