]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
0a6241b564184f37f9688487804f256a8762a871
[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     if (value.type == FcTypeString)
878     {
879         value.u.s = FcStrStaticName (value.u.s);
880         if (!value.u.s)
881             value.type = FcTypeVoid;
882     }
883     else
884         value = FcValueSave (value);
885     if (value.type == FcTypeVoid)
886         goto bail1;
887
888     /* quick and dirty hack to enable FcCompareFamily/FcCompareString
889      * speedup: only allow strings to be added under the FC_FAMILY,
890      * FC_FOUNDRY, FC_STYLE, FC_RASTERIZER keys.  
891      * and charsets under FC_CHARSET key.
892      * This is slightly semantically different from the old behaviour,
893      * but fonts shouldn't be getting non-strings here anyway.
894      * a better hack would use FcBaseObjectTypes to check all objects. */
895     objectPtr = FcObjectToPtr(object);
896     if ((objectPtr == FcObjectToPtr(FC_FAMILY)
897          || objectPtr == FcObjectToPtr(FC_FOUNDRY)
898          || objectPtr == FcObjectToPtr(FC_STYLE)
899          || objectPtr == FcObjectToPtr(FC_RASTERIZER))
900         && value.type != FcTypeString)
901         goto bail1;
902     if (objectPtr == FcObjectToPtr(FC_CHARSET)
903         && value.type != FcTypeCharSet)
904         goto bail1;
905
906     FcValueListPtrU(new)->value = value;
907     FcValueListPtrU(new)->binding = binding;
908     FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
909     
910     e = FcPatternInsertElt (p, object);
911     if (!e)
912         goto bail2;
913     
914     if (append)
915     {
916         for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
917             ;
918         *prev = new;
919     }
920     else
921     {
922         FcValueListPtrU(new)->next = e->values;
923         e->values = new;
924     }
925     
926     return FcTrue;
927
928 bail2:    
929     switch (value.type) {
930     case FcTypeString:
931         FcStrFree ((FcChar8 *) value.u.s);
932         break;
933     case FcTypeMatrix:
934         FcMatrixFree ((FcMatrix *) value.u.m);
935         break;
936     case FcTypeCharSet:
937         FcCharSetDestroy ((FcCharSet *) value.u.c);
938         break;
939     case FcTypeLangSet:
940         FcLangSetDestroy ((FcLangSet *) value.u.l);
941         break;
942     default:
943         break;
944     }
945 bail1:
946     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
947     free (FcValueListPtrU(new));
948 bail0:
949     return FcFalse;
950 }
951
952 FcBool
953 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
954 {
955     return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
956 }
957
958 FcBool
959 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
960 {
961     return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
962 }
963
964 FcBool
965 FcPatternDel (FcPattern *p, const char *object)
966 {
967     FcPatternElt   *e;
968
969     e = FcPatternFindElt (p, object);
970     if (!e)
971         return FcFalse;
972
973     /* destroy value */
974     FcValueListDestroy (e->values);
975     
976     /* shuffle existing ones down */
977     memmove (e, e+1, 
978              (FcPatternEltU(p->elts) + p->num - (e + 1)) * 
979              sizeof (FcPatternElt));
980     p->num--;
981     (FcPatternEltU(p->elts)+p->num)->object = 0;
982     (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
983     return FcTrue;
984 }
985
986 FcBool
987 FcPatternRemove (FcPattern *p, const char *object, int id)
988 {
989     FcPatternElt    *e;
990     FcValueListPtr  *prev, l;
991
992     e = FcPatternFindElt (p, object);
993     if (!e)
994         return FcFalse;
995     for (prev = &e->values; 
996          FcValueListPtrU(l = *prev); 
997          prev = &FcValueListPtrU(l)->next)
998     {
999         if (!id)
1000         {
1001             *prev = FcValueListPtrU(l)->next;
1002             FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
1003             FcValueListDestroy (l);
1004             if (!FcValueListPtrU(e->values))
1005                 FcPatternDel (p, object);
1006             return FcTrue;
1007         }
1008         id--;
1009     }
1010     return FcFalse;
1011 }
1012
1013 FcBool
1014 FcPatternAddInteger (FcPattern *p, const char *object, int i)
1015 {
1016     FcValue     v;
1017
1018     v.type = FcTypeInteger;
1019     v.u.i = i;
1020     return FcPatternAdd (p, object, v, FcTrue);
1021 }
1022
1023 FcBool
1024 FcPatternAddDouble (FcPattern *p, const char *object, double d)
1025 {
1026     FcValue     v;
1027
1028     v.type = FcTypeDouble;
1029     v.u.d = d;
1030     return FcPatternAdd (p, object, v, FcTrue);
1031 }
1032
1033
1034 FcBool
1035 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
1036 {
1037     FcValue     v;
1038
1039     if (!s)
1040     {
1041         v.type = FcTypeVoid;
1042         v.u.s = 0;
1043         return FcPatternAdd (p, object, v, FcTrue);
1044     }
1045
1046     v.type = FcTypeString;
1047     v.u.s = FcStrStaticName(s);
1048     return FcPatternAdd (p, object, v, FcTrue);
1049 }
1050
1051 FcBool
1052 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
1053 {
1054     FcValue     v;
1055
1056     v.type = FcTypeMatrix;
1057     v.u.m = s;
1058     return FcPatternAdd (p, object, v, FcTrue);
1059 }
1060
1061
1062 FcBool
1063 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
1064 {
1065     FcValue     v;
1066
1067     v.type = FcTypeBool;
1068     v.u.b = b;
1069     return FcPatternAdd (p, object, v, FcTrue);
1070 }
1071
1072 FcBool
1073 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
1074 {
1075     FcValue     v;
1076
1077     v.type = FcTypeCharSet;
1078     v.u.c = (FcCharSet *)c;
1079     return FcPatternAdd (p, object, v, FcTrue);
1080 }
1081
1082 FcBool
1083 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
1084 {
1085     FcValue     v;
1086
1087     v.type = FcTypeFTFace;
1088     v.u.f = (void *) f;
1089     return FcPatternAdd (p, object, v, FcTrue);
1090 }
1091
1092 FcBool
1093 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1094 {
1095     FcValue     v;
1096
1097     v.type = FcTypeLangSet;
1098     v.u.l = (FcLangSet *)ls;
1099     return FcPatternAdd (p, object, v, FcTrue);
1100 }
1101
1102 FcResult
1103 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
1104 {
1105     FcPatternElt   *e;
1106     FcValueListPtr l;
1107
1108     e = FcPatternFindElt (p, object);
1109     if (!e)
1110         return FcResultNoMatch;
1111     for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
1112     {
1113         if (!id)
1114         {
1115             *v = FcValueCanonicalize(&FcValueListPtrU(l)->value);
1116             return FcResultMatch;
1117         }
1118         id--;
1119     }
1120     return FcResultNoId;
1121 }
1122
1123 FcResult
1124 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
1125 {
1126     FcValue     v;
1127     FcResult    r;
1128
1129     r = FcPatternGet (p, object, id, &v);
1130     if (r != FcResultMatch)
1131         return r;
1132     switch (v.type) {
1133     case FcTypeDouble:
1134         *i = (int) v.u.d;
1135         break;
1136     case FcTypeInteger:
1137         *i = v.u.i;
1138         break;
1139     default:
1140         return FcResultTypeMismatch;
1141     }
1142     return FcResultMatch;
1143 }
1144
1145 FcResult
1146 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
1147 {
1148     FcValue     v;
1149     FcResult    r;
1150
1151     r = FcPatternGet (p, object, id, &v);
1152     if (r != FcResultMatch)
1153         return r;
1154     switch (v.type) {
1155     case FcTypeDouble:
1156         *d = v.u.d;
1157         break;
1158     case FcTypeInteger:
1159         *d = (double) v.u.i;
1160         break;
1161     default:
1162         return FcResultTypeMismatch;
1163     }
1164     return FcResultMatch;
1165 }
1166
1167 FcResult
1168 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1169 {
1170     FcValue     v;
1171     FcResult    r;
1172
1173     r = FcPatternGet (p, object, id, &v);
1174     if (r != FcResultMatch)
1175         return r;
1176     if (v.type != FcTypeString)
1177         return FcResultTypeMismatch;
1178
1179     if (FcObjectToPtr(object) == FcObjectToPtr(FC_FILE))
1180     {
1181         const char *fn, *fpath;
1182         FcChar8 *fname;
1183         int size;
1184
1185         fn = FcPatternFindFullFname(p);
1186         if (fn)
1187         {
1188             *s = (FcChar8 *) fn;
1189             return FcResultMatch;
1190         }
1191
1192         if (!p->bank)
1193         {
1194             *s = (FcChar8 *) v.u.s;
1195             return FcResultMatch;
1196         }
1197
1198         fpath = FcCacheFindBankDir (p->bank);
1199         size = strlen((char*)fpath) + 1 + strlen ((char *)v.u.s) + 1;
1200         fname = malloc (size);
1201         if (!fname)
1202             return FcResultOutOfMemory;
1203
1204         FcMemAlloc (FC_MEM_STRING, size);
1205         strcpy ((char *)fname, (char *)fpath);
1206         strcat ((char *)fname, "/");
1207         strcat ((char *)fname, (char *)v.u.s);
1208         
1209         FcPatternAddFullFname (p, (const char *)fname);
1210         *s = (FcChar8 *)fname;
1211         return FcResultMatch;
1212     }
1213
1214     *s = (FcChar8 *) v.u.s;
1215     return FcResultMatch;
1216 }
1217
1218 FcResult
1219 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1220 {
1221     FcValue     v;
1222     FcResult    r;
1223
1224     r = FcPatternGet (p, object, id, &v);
1225     if (r != FcResultMatch)
1226         return r;
1227     if (v.type != FcTypeMatrix)
1228         return FcResultTypeMismatch;
1229     *m = (FcMatrix *)v.u.m;
1230     return FcResultMatch;
1231 }
1232
1233
1234 FcResult
1235 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1236 {
1237     FcValue     v;
1238     FcResult    r;
1239
1240     r = FcPatternGet (p, object, id, &v);
1241     if (r != FcResultMatch)
1242         return r;
1243     if (v.type != FcTypeBool)
1244         return FcResultTypeMismatch;
1245     *b = v.u.b;
1246     return FcResultMatch;
1247 }
1248
1249 FcResult
1250 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1251 {
1252     FcValue     v;
1253     FcResult    r;
1254
1255     r = FcPatternGet (p, object, id, &v);
1256     if (r != FcResultMatch)
1257         return r;
1258     if (v.type != FcTypeCharSet)
1259         return FcResultTypeMismatch;
1260     *c = (FcCharSet *)v.u.c;
1261     return FcResultMatch;
1262 }
1263
1264 FcResult
1265 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1266 {
1267     FcValue     v;
1268     FcResult    r;
1269
1270     r = FcPatternGet (p, object, id, &v);
1271     if (r != FcResultMatch)
1272         return r;
1273     if (v.type != FcTypeFTFace)
1274         return FcResultTypeMismatch;
1275     *f = (FT_Face) v.u.f;
1276     return FcResultMatch;
1277 }
1278
1279 FcResult
1280 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1281 {
1282     FcValue     v;
1283     FcResult    r;
1284
1285     r = FcPatternGet (p, object, id, &v);
1286     if (r != FcResultMatch)
1287         return r;
1288     if (v.type != FcTypeLangSet)
1289         return FcResultTypeMismatch;
1290     *ls = (FcLangSet *)v.u.l;
1291     return FcResultMatch;
1292 }
1293
1294 FcPattern *
1295 FcPatternDuplicate (const FcPattern *orig)
1296 {
1297     FcPattern       *new;
1298     FcPatternElt    *e;
1299     int             i;
1300     FcValueListPtr  l;
1301
1302     new = FcPatternCreate ();
1303     if (!new)
1304         goto bail0;
1305
1306     e = FcPatternEltU(orig->elts);
1307
1308     for (i = 0; i < orig->num; i++)
1309     {
1310         for (l = (e + i)->values; 
1311              FcValueListPtrU(l); 
1312              l = FcValueListPtrU(l)->next)
1313             if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object), 
1314                                FcValueCanonicalize(&FcValueListPtrU(l)->value),
1315                                FcTrue))
1316                 goto bail1;
1317     }
1318     FcPatternTransferFullFname (new, orig);
1319
1320     return new;
1321
1322 bail1:
1323     FcPatternDestroy (new);
1324 bail0:
1325     return 0;
1326 }
1327
1328 void
1329 FcPatternReference (FcPattern *p)
1330 {
1331     if (p->ref != FC_REF_CONSTANT)
1332         p->ref++;
1333 }
1334
1335 FcPattern *
1336 FcPatternVaBuild (FcPattern *orig, va_list va)
1337 {
1338     FcPattern   *ret;
1339     
1340     FcPatternVapBuild (ret, orig, va);
1341     return ret;
1342 }
1343
1344 FcPattern *
1345 FcPatternBuild (FcPattern *orig, ...)
1346 {
1347     va_list     va;
1348     
1349     va_start (va, orig);
1350     FcPatternVapBuild (orig, orig, va);
1351     va_end (va);
1352     return orig;
1353 }
1354
1355 /*
1356  * Add all of the elements in 's' to 'p'
1357  */
1358 FcBool
1359 FcPatternAppend (FcPattern *p, FcPattern *s)
1360 {
1361     int             i;
1362     FcPatternElt    *e;
1363     FcValueListPtr  v;
1364     
1365     for (i = 0; i < s->num; i++)
1366     {
1367         e = FcPatternEltU(s->elts)+i;
1368         for (v = e->values; FcValueListPtrU(v); 
1369              v = FcValueListPtrU(v)->next)
1370         {
1371             if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
1372                                           FcValueCanonicalize(&FcValueListPtrU(v)->value), 
1373                                           FcValueListPtrU(v)->binding, FcTrue))
1374                 return FcFalse;
1375         }
1376     }
1377     return FcTrue;
1378 }
1379
1380 #define OBJECT_HASH_SIZE    31
1381 static struct objectBucket {
1382     struct objectBucket *next;
1383     FcChar32            hash;
1384 } *FcObjectBuckets[OBJECT_HASH_SIZE];
1385
1386 static FcBool
1387 FcStrHashed (const FcChar8 *name)
1388 {
1389     FcChar32            hash = FcStringHash (name);
1390     struct objectBucket **p;
1391     struct objectBucket *b;
1392
1393     for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1394         if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1395             return FcTrue;
1396     return FcFalse;
1397 }
1398
1399 const FcChar8 *
1400 FcStrStaticName (const FcChar8 *name)
1401 {
1402     FcChar32            hash = FcStringHash (name);
1403     struct objectBucket **p;
1404     struct objectBucket *b;
1405     int                 size;
1406
1407     for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1408         if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1409             return (FcChar8 *) (b + 1);
1410     size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
1411     b = malloc (size + sizeof (int));
1412     /* workaround glibc bug which reads strlen in groups of 4 */
1413     FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
1414     if (!b)
1415         return NULL;
1416     b->next = 0;
1417     b->hash = hash;
1418     strcpy ((char *) (b + 1), (char *)name);
1419     *p = b;
1420     return (FcChar8 *) (b + 1);
1421 }
1422
1423 static void
1424 FcStrStaticNameFini (void)
1425 {
1426     int i, size;
1427     struct objectBucket *b, *next;
1428     char *name;
1429
1430     for (i = 0; i < OBJECT_HASH_SIZE; i++)
1431     {
1432         for (b = FcObjectBuckets[i]; b; b = next)
1433         {
1434             next = b->next;
1435             name = (char *) (b + 1);
1436             size = sizeof (struct objectBucket) + strlen (name) + 1;
1437             FcMemFree (FC_MEM_STATICSTR, size);
1438             free (b);
1439         }
1440         FcObjectBuckets[i] = 0;
1441     }
1442 }
1443
1444 void
1445 FcPatternFini (void)
1446 {
1447     FcPatternBaseThawAll ();
1448     FcValueListThawAll ();
1449     FcStrStaticNameFini ();
1450     FcObjectStaticNameFini ();
1451 }
1452
1453 static FcPatternEltPtr
1454 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1455 {
1456     FcPatternEltPtr new;
1457     new.bank = FC_BANK_DYNAMIC;
1458     new.u.dyn = e;
1459     return new;
1460 }
1461
1462 static FcPatternEltPtr
1463 FcPatternEltPtrCreateStatic (int bank, int i)
1464 {
1465     FcPatternEltPtr new;
1466     new.bank = bank;
1467     new.u.stat = i;
1468     return new;
1469 }
1470
1471 static void
1472 FcStrNewBank (void);
1473 static int
1474 FcStrNeededBytes (const FcChar8 * s);
1475 static int
1476 FcStrNeededBytesAlign (void);
1477 static void *
1478 FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
1479 static const FcChar8 *
1480 FcStrSerialize (int bank, const FcChar8 * s);
1481 static void *
1482 FcStrUnserialize (FcCache * metadata, void *block_ptr);
1483
1484 static void
1485 FcValueListNewBank (void);
1486 static int
1487 FcValueListNeededBytes (FcValueList * vl);
1488 static int
1489 FcValueListNeededBytesAlign (void);
1490 static void *
1491 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
1492 static FcValueListPtr
1493 FcValueListSerialize(int bank, FcValueList *pi);
1494 static void *
1495 FcValueListUnserialize (FcCache * metadata, void *block_ptr);
1496
1497
1498 void
1499 FcPatternNewBank (void)
1500 {
1501     fcpattern_count = 0;
1502     fcpatternelt_count = 0;
1503
1504     FcStrNewBank();
1505     FcValueListNewBank();
1506 }
1507
1508 int
1509 FcPatternNeededBytes (FcPattern * p)
1510 {
1511     int i, cum = 0, c;
1512
1513     fcpattern_count++;
1514     fcpatternelt_count += p->num;
1515
1516     for (i = 0; i < p->num; i++)
1517     {
1518         c = FcValueListNeededBytes (FcValueListPtrU
1519                                     (((FcPatternEltU(p->elts)+i)->values)));
1520         if (c < 0)
1521             return c;
1522         cum += c;
1523     }
1524
1525     return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
1526 }
1527
1528 int
1529 FcPatternNeededBytesAlign (void)
1530 {
1531     return __alignof__ (FcPattern) + __alignof__ (FcPatternElt) + 
1532         FcValueListNeededBytesAlign ();
1533 }
1534
1535 static FcBool
1536 FcPatternEnsureBank (int bi)
1537 {
1538     FcPattern **pp;
1539     FcPatternElt **ep;
1540     int i;
1541
1542     if (!_fcPatterns || fcpattern_bank_count <= bi)
1543     {
1544         int new_count = bi + 4;
1545         pp = realloc (_fcPatterns, sizeof (FcPattern *) * new_count);
1546         if (!pp)
1547             return 0;
1548
1549         FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern *) * new_count);
1550         _fcPatterns = pp;
1551
1552         ep = realloc (_fcPatternElts, sizeof (FcPatternElt *) * new_count);
1553         if (!ep)
1554             return 0;
1555
1556         FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt *) * new_count);
1557         _fcPatternElts = ep;
1558
1559         for (i = fcpattern_bank_count; i < new_count; i++)
1560         {
1561             _fcPatterns[i] = 0;
1562             _fcPatternElts[i] = 0;
1563         }
1564
1565         fcpattern_bank_count = new_count;
1566     }
1567
1568     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
1569     return FcTrue;
1570 }
1571
1572 void *
1573 FcPatternDistributeBytes (FcCache * metadata, void * block_ptr)
1574 {
1575     int bi = FcCacheBankToIndex(metadata->bank);
1576
1577     if (!FcPatternEnsureBank(bi))
1578         return 0;
1579
1580     fcpattern_ptr = 0;
1581     block_ptr = ALIGN(block_ptr, FcPattern);
1582     _fcPatterns[bi] = (FcPattern *)block_ptr;
1583     block_ptr = (void *)((char *)block_ptr + 
1584                          (sizeof (FcPattern) * fcpattern_count));
1585     
1586     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
1587     fcpatternelt_ptr = 0;
1588     block_ptr = ALIGN(block_ptr, FcPatternElt);
1589     _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
1590     block_ptr = (void *)((char *)block_ptr + 
1591                          (sizeof (FcPatternElt) * fcpatternelt_count));
1592
1593     metadata->pattern_count = fcpattern_count;
1594     metadata->patternelt_count = fcpatternelt_count;
1595
1596     block_ptr = FcStrDistributeBytes (metadata, block_ptr);
1597     block_ptr = FcValueListDistributeBytes (metadata, block_ptr);
1598     return block_ptr;
1599 }
1600
1601 FcPattern *
1602 FcPatternSerialize (int bank, FcPattern *old)
1603 {
1604     FcPattern *p;
1605     FcPatternElt *e, *nep;
1606     FcValueList * nv;
1607     FcValueListPtr v, nv_head, nvp;
1608     int i, elts, bi = FcCacheBankToIndex(bank);
1609
1610     p = &_fcPatterns[bi][fcpattern_ptr++];
1611     p->bank = bank;
1612     elts = fcpatternelt_ptr;
1613     nep = &_fcPatternElts[bi][elts];
1614     if (!nep)
1615         return FcFalse;
1616
1617     fcpatternelt_ptr += old->num;
1618
1619     for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++) 
1620     {
1621         v = e->values;
1622         nvp = nv_head = FcValueListSerialize(bank, FcValueListPtrU(v));
1623         if (!FcValueListPtrU(nv_head))
1624             return 0;
1625         nv = FcValueListPtrU(nvp);
1626         
1627         for (;
1628              FcValueListPtrU(v);
1629              v = FcValueListPtrU(v)->next, 
1630                  nv = FcValueListPtrU(nv->next))
1631         {
1632             
1633             if (FcValueListPtrU(FcValueListPtrU(v)->next))
1634             {
1635                 nvp = FcValueListSerialize
1636                     (bank, FcValueListPtrU(FcValueListPtrU(v)->next));
1637                 nv->next = nvp;
1638             }
1639         }
1640         
1641         nep[i].values = nv_head;
1642         nep[i].object = e->object;
1643     }
1644
1645     p->elts = old->elts;
1646     p->elts = FcPatternEltPtrCreateStatic(bank, elts);
1647     p->size = old->num;
1648     p->num = old->num;
1649     p->ref = FC_REF_CONSTANT;
1650     return p;
1651 }
1652
1653 void *
1654 FcPatternUnserialize (FcCache * metadata, void *block_ptr)
1655 {
1656     int bi = FcCacheBankToIndex(metadata->bank);
1657     if (!FcPatternEnsureBank(bi))
1658         return FcFalse;
1659
1660     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata->pattern_count);
1661     block_ptr = ALIGN(block_ptr, FcPattern);
1662     _fcPatterns[bi] = (FcPattern *)block_ptr;
1663     block_ptr = (void *)((char *)block_ptr + 
1664                          (sizeof (FcPattern) * metadata->pattern_count));
1665     
1666     FcMemAlloc (FC_MEM_PATELT, 
1667                 sizeof (FcPatternElt) * metadata->patternelt_count);
1668     block_ptr = ALIGN(block_ptr, FcPatternElt);
1669     _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
1670     block_ptr = (void *)((char *)block_ptr + 
1671                          (sizeof (FcPatternElt) * metadata->patternelt_count));
1672         
1673     block_ptr = FcStrUnserialize (metadata, block_ptr);
1674     block_ptr = FcValueListUnserialize (metadata, block_ptr);
1675
1676     return block_ptr;
1677 }
1678
1679 static void
1680 FcValueListNewBank (void)
1681 {
1682     fcvaluelist_count = 0;
1683
1684     FcCharSetNewBank();
1685     FcLangSetNewBank();
1686 }
1687
1688 static int
1689 FcValueListNeededBytes (FcValueList *p)
1690 {
1691     FcValueList *vl;
1692     int cum = 0;
1693
1694     for (vl = p;
1695          vl; 
1696          vl = FcValueListPtrU(vl->next))
1697     {
1698         FcValue v = FcValueCanonicalize(&vl->value); // unserialize just in case
1699
1700         switch (v.type)
1701         {
1702         case FcTypeCharSet:
1703             cum += FcCharSetNeededBytes(v.u.c);
1704             break;
1705         case FcTypeLangSet:
1706             cum += FcLangSetNeededBytes(v.u.l);
1707             break;
1708         case FcTypeString:
1709             cum += FcStrNeededBytes(v.u.s);
1710         default:
1711             break;
1712         }
1713         fcvaluelist_count++;
1714         cum += sizeof (FcValueList);
1715     }
1716     
1717     return cum;
1718 }
1719
1720 static int
1721 FcValueListNeededBytesAlign (void)
1722 {
1723     return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() + 
1724         FcStrNeededBytesAlign() + __alignof__ (FcValueList);
1725 }
1726
1727 static FcBool
1728 FcValueListEnsureBank (int bi)
1729 {
1730     FcValueList **pvl;
1731
1732     if (!_fcValueLists || fcvaluelist_bank_count <= bi)
1733     {
1734         int new_count = bi + 2, i;
1735
1736         pvl = realloc (_fcValueLists, sizeof (FcValueList *) * new_count);
1737         if (!pvl)
1738             return FcFalse;
1739
1740         FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList *) * new_count);
1741
1742         _fcValueLists = pvl;
1743         for (i = fcvaluelist_bank_count; i < new_count; i++)
1744             _fcValueLists[i] = 0;
1745
1746         fcvaluelist_bank_count = new_count;
1747     }
1748     return FcTrue;
1749 }
1750
1751 static void *
1752 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
1753 {
1754     int bi = FcCacheBankToIndex(metadata->bank);
1755
1756     if (!FcValueListEnsureBank(bi))
1757         return 0;
1758
1759     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1760     fcvaluelist_ptr = 0;
1761     block_ptr = ALIGN(block_ptr, FcValueList);
1762     _fcValueLists[bi] = (FcValueList *)block_ptr;
1763     block_ptr = (void *)((char *)block_ptr + 
1764                          (sizeof (FcValueList) * fcvaluelist_count));
1765     metadata->valuelist_count = fcvaluelist_count;
1766
1767     block_ptr = FcCharSetDistributeBytes(metadata, block_ptr);
1768     block_ptr = FcLangSetDistributeBytes(metadata, block_ptr);
1769
1770     return block_ptr;
1771 }
1772
1773 static FcValueListPtr
1774 FcValueListSerialize(int bank, FcValueList *pi)
1775 {
1776     FcValueListPtr new; 
1777     FcValue * v;
1778     int bi = FcCacheBankToIndex(bank);
1779
1780     if (!pi)
1781     {
1782         new.bank = FC_BANK_DYNAMIC;
1783         new.u.dyn = 0;
1784         return new;
1785     }
1786
1787     _fcValueLists[bi][fcvaluelist_ptr] = *pi;
1788     new.bank = bank;
1789     new.u.stat = fcvaluelist_ptr++;
1790     _fcValueLists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
1791     v = &_fcValueLists[bi][new.u.stat].value;
1792     switch (v->type)
1793     {
1794     case FcTypeString:
1795         if (v->u.s)
1796         {
1797             const FcChar8 * s = FcStrSerialize(bank, v->u.s);
1798             if (!s)
1799                 return FcValueListPtrCreateDynamic(pi);
1800             v->u.s_off = s - (const FcChar8 *)v;
1801             v->type |= FC_STORAGE_STATIC;
1802         }
1803         break;
1804     case FcTypeMatrix:
1805         break;
1806     case FcTypeCharSet:
1807         if (v->u.c)
1808         {
1809             FcCharSet * c = FcCharSetSerialize(bank, (FcCharSet *)v->u.c);
1810             if (!c)
1811                 return FcValueListPtrCreateDynamic(pi);
1812             v->u.c_off = (char *)c - (char *)v;
1813             v->type |= FC_STORAGE_STATIC;
1814         }
1815         break;
1816     case FcTypeLangSet:
1817         if (v->u.l)
1818         {
1819             FcLangSet * l = FcLangSetSerialize(bank, (FcLangSet *)v->u.l);
1820             if (!l)
1821                 return FcValueListPtrCreateDynamic(pi);
1822             v->u.l_off = (char *)l - (char *)v;
1823             v->type |= FC_STORAGE_STATIC;
1824         }
1825         break;
1826     default:
1827         break;
1828     }
1829     return new;
1830 }
1831
1832 static void *
1833 FcValueListUnserialize (FcCache * metadata, void *block_ptr)
1834 {
1835     int bi = FcCacheBankToIndex(metadata->bank);
1836
1837     if (!FcValueListEnsureBank(bi))
1838         return 0;
1839
1840     FcMemAlloc (FC_MEM_VALLIST, 
1841                 sizeof (FcValueList) * metadata->valuelist_count);
1842     block_ptr = ALIGN(block_ptr, FcValueList);
1843     _fcValueLists[bi] = (FcValueList *)block_ptr;
1844     block_ptr = (void *)((char *)block_ptr + 
1845                          (sizeof (FcValueList) * metadata->valuelist_count));
1846
1847     block_ptr = FcCharSetUnserialize(metadata, block_ptr);
1848     block_ptr = FcLangSetUnserialize(metadata, block_ptr);
1849
1850     return block_ptr;
1851 }
1852
1853 FcValueListPtr
1854 FcValueListPtrCreateDynamic(FcValueList * p)
1855 {
1856     FcValueListPtr r; 
1857
1858     r.bank = FC_BANK_DYNAMIC; 
1859     r.u.dyn = p;
1860     return r;
1861 }
1862
1863 static FcChar8 ** static_strs;
1864 static int static_str_bank_count = 0, fcstr_ptr, fcstr_count;
1865
1866 static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE];
1867
1868 static void
1869 FcStrNewBank (void)
1870 {
1871     int i, size;
1872     struct objectBucket *b, *next;
1873     char *name;
1874
1875     for (i = 0; i < OBJECT_HASH_SIZE; i++)
1876     {
1877         for (b = FcStrBuckets[i]; b; b = next)
1878         {
1879             next = b->next;
1880             name = (char *) (b + 1);
1881             size = sizeof (struct objectBucket) + strlen (name) + 1;
1882             FcMemFree (FC_MEM_STATICSTR, size);
1883             free (b);
1884         }
1885         FcStrBuckets[i] = 0;
1886     }
1887
1888     fcstr_count = 0;
1889 }
1890
1891 static int
1892 FcStrNeededBytes (const FcChar8 * s)
1893 {
1894     FcChar32            hash = FcStringHash ((const FcChar8 *) s);
1895     struct objectBucket **p;
1896     struct objectBucket *b;
1897     int                 size;
1898     FcChar8 *const null = 0;
1899
1900     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1901         if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1902             return 0;
1903     size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *);
1904     b = malloc (size);
1905     FcMemAlloc (FC_MEM_STATICSTR, size);
1906     if (!b)
1907         return -1;
1908     b->next = 0;
1909     b->hash = hash;
1910     strcpy ((char *) (b + 1), (char *)s);
1911
1912     /* Yes, the following line is convoluted.  However, it is
1913      * incorrect to replace the with a memset, because the C
1914      * specification doesn't guarantee that the null pointer is
1915      * the same as the zero bit pattern. */
1916     /* Misaligned pointers are not guaranteed to work, either! */
1917     memcpy (((char *) (b + 1) + strlen((char *)s) + 1), &null, sizeof (null));
1918     *p = b;
1919
1920     fcstr_count += strlen((char *)s) + 1;
1921     return strlen((char *)s) + 1;
1922 }
1923
1924 static int
1925 FcStrNeededBytesAlign (void)
1926 {
1927     return __alignof__ (char);
1928 }
1929
1930 static FcBool
1931 FcStrEnsureBank (int bi)
1932 {
1933     FcChar8 ** ss;
1934
1935     if (!static_strs || static_str_bank_count <= bi)
1936     {
1937         int new_count = bi + 4, i;
1938         ss = realloc (static_strs, sizeof (const char *) * new_count);
1939         if (!ss)
1940             return FcFalse;
1941
1942         FcMemAlloc (FC_MEM_STRING, sizeof (const char *) * (new_count-static_str_bank_count));
1943         static_strs = ss;
1944
1945         for (i = static_str_bank_count; i < new_count; i++)
1946             static_strs[i] = 0;
1947         static_str_bank_count = new_count;
1948     }
1949     return FcTrue;
1950 }
1951
1952 static void *
1953 FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
1954 {
1955     int bi = FcCacheBankToIndex(metadata->bank);
1956     if (!FcStrEnsureBank(bi)) 
1957         return 0;
1958
1959     FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
1960     block_ptr = ALIGN (block_ptr, FcChar8);
1961     static_strs[bi] = (FcChar8 *)block_ptr;
1962     block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
1963     metadata->str_count = fcstr_count;
1964     fcstr_ptr = 0;
1965
1966     return block_ptr;
1967 }
1968
1969 static const FcChar8 *
1970 FcStrSerialize (int bank, const FcChar8 * s)
1971 {
1972     FcChar32            hash = FcStringHash ((const FcChar8 *) s);
1973     struct objectBucket **p;
1974     struct objectBucket *b;
1975     int bi = FcCacheBankToIndex(bank);
1976
1977     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1978         if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1979         {
1980             FcChar8 * t;
1981             memcpy (&t, ((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1, sizeof (FcChar8 *));
1982             if (!t)
1983             {
1984                 strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
1985                 t = static_strs[bi] + fcstr_ptr;
1986                 memcpy ((FcChar8 *) (b + 1) + strlen((char *)s) + 1, &t, sizeof (FcChar8 *));
1987                 fcstr_ptr += strlen((char *)s) + 1;
1988                 memcpy (&t, ((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1, sizeof (FcChar8 *));
1989             }
1990             return t;
1991         }
1992     return 0;
1993 }
1994
1995 static void *
1996 FcStrUnserialize (FcCache * metadata, void *block_ptr)
1997 {
1998     int bi = FcCacheBankToIndex(metadata->bank);
1999     if (!FcStrEnsureBank(bi))
2000         return 0;
2001
2002     FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata->str_count);
2003     block_ptr = ALIGN (block_ptr, FcChar8);
2004     static_strs[bi] = (FcChar8 *)block_ptr;
2005     block_ptr = (void *)((char *)block_ptr + 
2006                          (sizeof (char) * metadata->str_count));
2007
2008     return block_ptr;
2009 }
2010
2011 /* we don't store these in the FcPattern itself because
2012  * we don't want to serialize the directory names */
2013
2014 /* I suppose this should be cleaned upon termination, too... */
2015 typedef struct _FcPatternDirMapping {
2016     const FcPattern     *p;
2017     const char *fname;
2018 } FcPatternDirMapping;
2019
2020 #define PATTERNDIR_HASH_SIZE    31
2021 static struct patternDirBucket {
2022     struct patternDirBucket     *next;
2023     FcPatternDirMapping         m;
2024 } FcPatternDirBuckets[PATTERNDIR_HASH_SIZE];
2025
2026 void
2027 FcPatternAddFullFname (const FcPattern *p, const char *fname)
2028 {
2029     struct patternDirBucket     *pb;
2030
2031     /* N.B. FcPatternHash fails, since it's contents-based, not
2032      * address-based, and we're in the process of mutating the FcPattern. */
2033     for (pb = &FcPatternDirBuckets
2034              [((unsigned long)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
2035          pb->m.p != p && pb->next; 
2036          pb = pb->next)
2037         ;
2038
2039     if (pb->m.p == p)
2040     {
2041         pb->m.fname = fname;
2042         return;
2043     }
2044
2045     pb->next = malloc (sizeof (struct patternDirBucket));
2046     if (!pb->next)
2047         return;
2048     FcMemAlloc (FC_MEM_CACHE, sizeof (struct patternDirBucket));
2049
2050     pb->next->next = 0;
2051     pb->next->m.p = p;
2052     pb->next->m.fname = fname;
2053 }
2054
2055 static const char *
2056 FcPatternFindFullFname (const FcPattern *p)
2057 {
2058     struct patternDirBucket     *pb;
2059
2060     for (pb = &FcPatternDirBuckets
2061              [((unsigned long)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE]; 
2062          pb; pb = pb->next)
2063         if (pb->m.p == p)
2064             return pb->m.fname;
2065
2066     return 0;
2067 }
2068
2069 void
2070 FcPatternTransferFullFname (const FcPattern *new, const FcPattern *orig)
2071 {
2072     FcChar8 * s;
2073     FcPatternGetString (orig, FC_FILE, 0, &s);
2074     FcPatternAddFullFname (new, 
2075                            (char *)FcStrCopy 
2076                            ((FcChar8 *)FcPatternFindFullFname(orig)));
2077 }