]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcpat.c
Fix additional memory leaks reported by Ronny V. Vindenes: don't invoke
[fontconfig.git] / src / fcpat.c
index 9600d33a614564d2ebc1dae1c4539e6155aae772..0a6241b564184f37f9688487804f256a8762a871 100644 (file)
 #include <assert.h>
 #include "fcint.h"
 
-static FcPattern ** fcpatterns = 0;
+static FcPattern ** _fcPatterns = 0;
 static int fcpattern_bank_count = 0, fcpattern_ptr, fcpattern_count;
-static FcPatternElt ** fcpatternelts = 0;
+FcPatternElt ** _fcPatternElts = 0;
 static int fcpatternelt_ptr, fcpatternelt_count;
-static FcValueList ** fcvaluelists = 0;
+FcValueList ** _fcValueLists = 0;
 static int fcvaluelist_bank_count = 0, fcvaluelist_ptr, fcvaluelist_count;
 
 static FcPatternEltPtr
 FcPatternEltPtrCreateDynamic (FcPatternElt * e);
+static FcBool
+FcStrHashed (const FcChar8 *name);
+
+static const char *
+FcPatternFindFullFname (const FcPattern *p);
+
+/* If you are trying to duplicate an FcPattern which will be used for
+ * rendering, be aware that (internally) you also have to use
+ * FcPatternTransferFullFname to transfer the associated filename.  If
+ * you are copying the font (externally) using FcPatternGetString,
+ * then everything's fine; this caveat only applies if you're copying
+ * the bits individually.  */
 
 FcPattern *
 FcPatternCreate (void)
@@ -59,7 +71,8 @@ FcValueDestroy (FcValue v)
 {
     switch (v.type) {
     case FcTypeString:
-       FcStrFree ((FcChar8 *) v.u.s);
+        if (!FcStrHashed (v.u.s))
+            FcStrFree ((FcChar8 *) v.u.s);
        break;
     case FcTypeMatrix:
        FcMatrixFree ((FcMatrix *) v.u.m);
@@ -140,7 +153,8 @@ FcValueListDestroy (FcValueListPtr l)
     {
        switch (FcValueListPtrU(l)->value.type) {
        case FcTypeString:
-           FcStrFree ((FcChar8 *)FcValueListPtrU(l)->value.u.s);
+            if (!FcStrHashed ((FcChar8 *)FcValueListPtrU(l)->value.u.s))
+                FcStrFree ((FcChar8 *)FcValueListPtrU(l)->value.u.s);
            break;
        case FcTypeMatrix:
            FcMatrixFree ((FcMatrix *)FcValueListPtrU(l)->value.u.m);
@@ -298,6 +312,12 @@ FcPatternDestroy (FcPattern *p)
     if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
        return;
 
+    if (FcPatternFindFullFname (p))
+    {
+       FcStrFree ((FcChar8 *)FcPatternFindFullFname (p));
+       FcPatternAddFullFname (p, 0);
+    }
+
     for (i = 0; i < p->num; i++)
        FcValueListDestroy ((FcPatternEltU(p->elts)+i)->values);
 
@@ -331,7 +351,7 @@ typedef union _FcValueListAlign {
 
 static int         FcValueListFrozenCount[FcTypeLangSet + 1];
 static int         FcValueListFrozenBytes[FcTypeLangSet + 1];
-static char        *FcValueListFrozenName[] = {
+static char        FcValueListFrozenName[][8] = {
     "Void", 
     "Integer", 
     "Double", 
@@ -577,6 +597,9 @@ FcPatternBaseFreeze (FcPattern *b)
            (FcPatternEltU(b->elts)+i)->object;
     }
 
+    if (FcPatternFindElt (b, FC_FILE))
+       FcPatternTransferFullFname (ep, b);
+
     ent->hash = hash;
     ent->next = *bucket;
     *bucket = ent;
@@ -644,6 +667,10 @@ FcPatternFreeze (FcPattern *p)
        if (!FcValueListPtrU((FcPatternEltU(p->elts)+i)->values))
            goto bail;
     }
+
+    if (FcPatternFindElt (p, FC_FILE))
+       FcPatternTransferFullFname (b, p);
+
     /*
      * Freeze base
      */
@@ -833,7 +860,8 @@ FcPatternAddWithBinding  (FcPattern     *p,
 {
     FcPatternElt   *e;
     FcValueListPtr new, *prev;
-    FcValueList *  newp;
+    FcValueList    *newp;
+    FcObjectPtr    objectPtr;
 
     if (p->ref == FC_REF_CONSTANT)
        goto bail0;
@@ -846,10 +874,35 @@ FcPatternAddWithBinding  (FcPattern           *p,
     new = FcValueListPtrCreateDynamic(newp);
     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
     /* dup string */
-    value = FcValueSave (value);
+    if (value.type == FcTypeString)
+    {
+       value.u.s = FcStrStaticName (value.u.s);
+       if (!value.u.s)
+           value.type = FcTypeVoid;
+    }
+    else
+       value = FcValueSave (value);
     if (value.type == FcTypeVoid)
        goto bail1;
 
+    /* quick and dirty hack to enable FcCompareFamily/FcCompareString
+     * speedup: only allow strings to be added under the FC_FAMILY,
+     * FC_FOUNDRY, FC_STYLE, FC_RASTERIZER keys.  
+     * and charsets under FC_CHARSET key.
+     * This is slightly semantically different from the old behaviour,
+     * but fonts shouldn't be getting non-strings here anyway.
+     * a better hack would use FcBaseObjectTypes to check all objects. */
+    objectPtr = FcObjectToPtr(object);
+    if ((objectPtr == FcObjectToPtr(FC_FAMILY)
+         || objectPtr == FcObjectToPtr(FC_FOUNDRY)
+         || objectPtr == FcObjectToPtr(FC_STYLE)
+         || objectPtr == FcObjectToPtr(FC_RASTERIZER))
+        && value.type != FcTypeString)
+        goto bail1;
+    if (objectPtr == FcObjectToPtr(FC_CHARSET)
+        && value.type != FcTypeCharSet)
+        goto bail1;
+
     FcValueListPtrU(new)->value = value;
     FcValueListPtrU(new)->binding = binding;
     FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
@@ -983,6 +1036,13 @@ FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
 {
     FcValue    v;
 
+    if (!s)
+    {
+       v.type = FcTypeVoid;
+       v.u.s = 0;
+       return FcPatternAdd (p, object, v, FcTrue);
+    }
+
     v.type = FcTypeString;
     v.u.s = FcStrStaticName(s);
     return FcPatternAdd (p, object, v, FcTrue);
@@ -1115,6 +1175,42 @@ FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s
        return r;
     if (v.type != FcTypeString)
         return FcResultTypeMismatch;
+
+    if (FcObjectToPtr(object) == FcObjectToPtr(FC_FILE))
+    {
+       const char *fn, *fpath;
+       FcChar8 *fname;
+       int size;
+
+       fn = FcPatternFindFullFname(p);
+       if (fn)
+       {
+           *s = (FcChar8 *) fn;
+           return FcResultMatch;
+       }
+
+       if (!p->bank)
+       {
+           *s = (FcChar8 *) v.u.s;
+           return FcResultMatch;
+       }
+
+       fpath = FcCacheFindBankDir (p->bank);
+       size = strlen((char*)fpath) + 1 + strlen ((char *)v.u.s) + 1;
+       fname = malloc (size);
+       if (!fname)
+           return FcResultOutOfMemory;
+
+       FcMemAlloc (FC_MEM_STRING, size);
+       strcpy ((char *)fname, (char *)fpath);
+       strcat ((char *)fname, "/");
+       strcat ((char *)fname, (char *)v.u.s);
+       
+       FcPatternAddFullFname (p, (const char *)fname);
+       *s = (FcChar8 *)fname;
+       return FcResultMatch;
+    }
+
     *s = (FcChar8 *) v.u.s;
     return FcResultMatch;
 }
@@ -1215,9 +1311,11 @@ FcPatternDuplicate (const FcPattern *orig)
             FcValueListPtrU(l); 
             l = FcValueListPtrU(l)->next)
            if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object), 
-                               FcValueListPtrU(l)->value, FcTrue))
+                               FcValueCanonicalize(&FcValueListPtrU(l)->value),
+                              FcTrue))
                goto bail1;
     }
+    FcPatternTransferFullFname (new, orig);
 
     return new;
 
@@ -1285,6 +1383,19 @@ static struct objectBucket {
     FcChar32           hash;
 } *FcObjectBuckets[OBJECT_HASH_SIZE];
 
+static FcBool
+FcStrHashed (const FcChar8 *name)
+{
+    FcChar32           hash = FcStringHash (name);
+    struct objectBucket        **p;
+    struct objectBucket        *b;
+
+    for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
+       if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
+            return FcTrue;
+    return FcFalse;
+}
+
 const FcChar8 *
 FcStrStaticName (const FcChar8 *name)
 {
@@ -1297,8 +1408,9 @@ FcStrStaticName (const FcChar8 *name)
        if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
            return (FcChar8 *) (b + 1);
     size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
-    b = malloc (size);
-    FcMemAlloc (FC_MEM_STATICSTR, size);
+    b = malloc (size + sizeof (int));
+    /* workaround glibc bug which reads strlen in groups of 4 */
+    FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
     if (!b)
         return NULL;
     b->next = 0;
@@ -1338,15 +1450,6 @@ FcPatternFini (void)
     FcObjectStaticNameFini ();
 }
 
-FcPatternElt *
-FcPatternEltU (FcPatternEltPtr pei)
-{
-    if (pei.bank == FC_BANK_DYNAMIC)
-       return pei.u.dyn;
-
-    return &fcpatternelts[FcCacheBankToIndex(pei.bank)][pei.u.stat];
-}
-
 static FcPatternEltPtr
 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
 {
@@ -1369,23 +1472,27 @@ static void
 FcStrNewBank (void);
 static int
 FcStrNeededBytes (const FcChar8 * s);
+static int
+FcStrNeededBytesAlign (void);
 static void *
 FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
 static const FcChar8 *
 FcStrSerialize (int bank, const FcChar8 * s);
 static void *
-FcStrUnserialize (FcCache metadata, void *block_ptr);
+FcStrUnserialize (FcCache metadata, void *block_ptr);
 
 static void
 FcValueListNewBank (void);
 static int
 FcValueListNeededBytes (FcValueList * vl);
+static int
+FcValueListNeededBytesAlign (void);
 static void *
 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
 static FcValueListPtr
 FcValueListSerialize(int bank, FcValueList *pi);
 static void *
-FcValueListUnserialize (FcCache metadata, void *block_ptr);
+FcValueListUnserialize (FcCache metadata, void *block_ptr);
 
 
 void
@@ -1418,6 +1525,13 @@ FcPatternNeededBytes (FcPattern * p)
     return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
 }
 
+int
+FcPatternNeededBytesAlign (void)
+{
+    return __alignof__ (FcPattern) + __alignof__ (FcPatternElt) + 
+       FcValueListNeededBytesAlign ();
+}
+
 static FcBool
 FcPatternEnsureBank (int bi)
 {
@@ -1425,27 +1539,27 @@ FcPatternEnsureBank (int bi)
     FcPatternElt **ep;
     int i;
 
-    if (!fcpatterns || fcpattern_bank_count <= bi)
+    if (!_fcPatterns || fcpattern_bank_count <= bi)
     {
        int new_count = bi + 4;
-       pp = realloc (fcpatterns, sizeof (FcPattern *) * new_count);
+       pp = realloc (_fcPatterns, sizeof (FcPattern *) * new_count);
        if (!pp)
            return 0;
 
        FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern *) * new_count);
-       fcpatterns = pp;
+       _fcPatterns = pp;
 
-       ep = realloc (fcpatternelts, sizeof (FcPatternElt *) * new_count);
+       ep = realloc (_fcPatternElts, sizeof (FcPatternElt *) * new_count);
        if (!ep)
            return 0;
 
        FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt *) * new_count);
-       fcpatternelts = ep;
+       _fcPatternElts = ep;
 
        for (i = fcpattern_bank_count; i < new_count; i++)
        {
-           fcpatterns[i] = 0;
-           fcpatternelts[i] = 0;
+           _fcPatterns[i] = 0;
+           _fcPatternElts[i] = 0;
        }
 
        fcpattern_bank_count = new_count;
@@ -1464,13 +1578,15 @@ FcPatternDistributeBytes (FcCache * metadata, void * block_ptr)
        return 0;
 
     fcpattern_ptr = 0;
-    fcpatterns[bi] = (FcPattern *)block_ptr;
+    block_ptr = ALIGN(block_ptr, FcPattern);
+    _fcPatterns[bi] = (FcPattern *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcPattern) * fcpattern_count));
     
     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
     fcpatternelt_ptr = 0;
-    fcpatternelts[bi] = (FcPatternElt *)block_ptr;
+    block_ptr = ALIGN(block_ptr, FcPatternElt);
+    _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcPatternElt) * fcpatternelt_count));
 
@@ -1491,10 +1607,10 @@ FcPatternSerialize (int bank, FcPattern *old)
     FcValueListPtr v, nv_head, nvp;
     int i, elts, bi = FcCacheBankToIndex(bank);
 
-    p = &fcpatterns[bi][fcpattern_ptr++];
+    p = &_fcPatterns[bi][fcpattern_ptr++];
     p->bank = bank;
     elts = fcpatternelt_ptr;
-    nep = &fcpatternelts[bi][elts];
+    nep = &_fcPatternElts[bi][elts];
     if (!nep)
        return FcFalse;
 
@@ -1535,22 +1651,24 @@ FcPatternSerialize (int bank, FcPattern *old)
 }
 
 void *
-FcPatternUnserialize (FcCache metadata, void *block_ptr)
+FcPatternUnserialize (FcCache metadata, void *block_ptr)
 {
-    int bi = FcCacheBankToIndex(metadata.bank);
+    int bi = FcCacheBankToIndex(metadata->bank);
     if (!FcPatternEnsureBank(bi))
        return FcFalse;
 
-    FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata.pattern_count);
-    fcpatterns[bi] = (FcPattern *)block_ptr;
+    FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata->pattern_count);
+    block_ptr = ALIGN(block_ptr, FcPattern);
+    _fcPatterns[bi] = (FcPattern *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
-                        (sizeof (FcPattern) * metadata.pattern_count));
+                        (sizeof (FcPattern) * metadata->pattern_count));
     
     FcMemAlloc (FC_MEM_PATELT, 
-               sizeof (FcPatternElt) * metadata.patternelt_count);
-    fcpatternelts[bi] = (FcPatternElt *)block_ptr;
+               sizeof (FcPatternElt) * metadata->patternelt_count);
+    block_ptr = ALIGN(block_ptr, FcPatternElt);
+    _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
-                        (sizeof (FcPatternElt) * metadata.patternelt_count));
+                        (sizeof (FcPatternElt) * metadata->patternelt_count));
        
     block_ptr = FcStrUnserialize (metadata, block_ptr);
     block_ptr = FcValueListUnserialize (metadata, block_ptr);
@@ -1599,24 +1717,31 @@ FcValueListNeededBytes (FcValueList *p)
     return cum;
 }
 
+static int
+FcValueListNeededBytesAlign (void)
+{
+    return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() + 
+       FcStrNeededBytesAlign() + __alignof__ (FcValueList);
+}
+
 static FcBool
 FcValueListEnsureBank (int bi)
 {
     FcValueList **pvl;
 
-    if (!fcvaluelists || fcvaluelist_bank_count <= bi)
+    if (!_fcValueLists || fcvaluelist_bank_count <= bi)
     {
        int new_count = bi + 2, i;
 
-       pvl = realloc (fcvaluelists, sizeof (FcValueList *) * new_count);
+       pvl = realloc (_fcValueLists, sizeof (FcValueList *) * new_count);
        if (!pvl)
            return FcFalse;
 
        FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList *) * new_count);
 
-       fcvaluelists = pvl;
+       _fcValueLists = pvl;
        for (i = fcvaluelist_bank_count; i < new_count; i++)
-           fcvaluelists[i] = 0;
+           _fcValueLists[i] = 0;
 
        fcvaluelist_bank_count = new_count;
     }
@@ -1633,7 +1758,8 @@ FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
 
     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
     fcvaluelist_ptr = 0;
-    fcvaluelists[bi] = (FcValueList *)block_ptr;
+    block_ptr = ALIGN(block_ptr, FcValueList);
+    _fcValueLists[bi] = (FcValueList *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (sizeof (FcValueList) * fcvaluelist_count));
     metadata->valuelist_count = fcvaluelist_count;
@@ -1658,10 +1784,11 @@ FcValueListSerialize(int bank, FcValueList *pi)
        return new;
     }
 
-    fcvaluelists[bi][fcvaluelist_ptr] = *pi;
+    _fcValueLists[bi][fcvaluelist_ptr] = *pi;
     new.bank = bank;
     new.u.stat = fcvaluelist_ptr++;
-    v = &fcvaluelists[bi][new.u.stat].value;
+    _fcValueLists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
+    v = &_fcValueLists[bi][new.u.stat].value;
     switch (v->type)
     {
     case FcTypeString:
@@ -1703,18 +1830,19 @@ FcValueListSerialize(int bank, FcValueList *pi)
 }
 
 static void *
-FcValueListUnserialize (FcCache metadata, void *block_ptr)
+FcValueListUnserialize (FcCache metadata, void *block_ptr)
 {
-    int bi = FcCacheBankToIndex(metadata.bank);
+    int bi = FcCacheBankToIndex(metadata->bank);
 
     if (!FcValueListEnsureBank(bi))
        return 0;
 
     FcMemAlloc (FC_MEM_VALLIST, 
-               sizeof (FcValueList) * metadata.valuelist_count);
-    fcvaluelists[bi] = (FcValueList *)block_ptr;
+               sizeof (FcValueList) * metadata->valuelist_count);
+    block_ptr = ALIGN(block_ptr, FcValueList);
+    _fcValueLists[bi] = (FcValueList *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
-                        (sizeof (FcValueList) * metadata.valuelist_count));
+                        (sizeof (FcValueList) * metadata->valuelist_count));
 
     block_ptr = FcCharSetUnserialize(metadata, block_ptr);
     block_ptr = FcLangSetUnserialize(metadata, block_ptr);
@@ -1722,15 +1850,6 @@ FcValueListUnserialize (FcCache metadata, void *block_ptr)
     return block_ptr;
 }
 
-FcValueList * 
-FcValueListPtrU (FcValueListPtr pi)
-{
-    if (pi.bank == FC_BANK_DYNAMIC)
-        return pi.u.dyn;
-
-    return &fcvaluelists[FcCacheBankToIndex(pi.bank)][pi.u.stat];
-}
-
 FcValueListPtr
 FcValueListPtrCreateDynamic(FcValueList * p)
 {
@@ -1776,6 +1895,7 @@ FcStrNeededBytes (const FcChar8 * s)
     struct objectBucket **p;
     struct objectBucket *b;
     int                 size;
+    FcChar8 *const null = 0;
 
     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
         if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
@@ -1788,13 +1908,25 @@ FcStrNeededBytes (const FcChar8 * s)
     b->next = 0;
     b->hash = hash;
     strcpy ((char *) (b + 1), (char *)s);
-    *(char **)((char *) (b + 1) + strlen((char *)s) + 1) = 0;
+
+    /* Yes, the following line is convoluted.  However, it is
+     * incorrect to replace the with a memset, because the C
+     * specification doesn't guarantee that the null pointer is
+     * the same as the zero bit pattern. */
+    /* Misaligned pointers are not guaranteed to work, either! */
+    memcpy (((char *) (b + 1) + strlen((char *)s) + 1), &null, sizeof (null));
     *p = b;
 
     fcstr_count += strlen((char *)s) + 1;
     return strlen((char *)s) + 1;
 }
 
+static int
+FcStrNeededBytesAlign (void)
+{
+    return __alignof__ (char);
+}
+
 static FcBool
 FcStrEnsureBank (int bi)
 {
@@ -1825,6 +1957,7 @@ FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
        return 0;
 
     FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
+    block_ptr = ALIGN (block_ptr, FcChar8);
     static_strs[bi] = (FcChar8 *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
     metadata->str_count = fcstr_count;
@@ -1844,13 +1977,15 @@ FcStrSerialize (int bank, const FcChar8 * s)
     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
         if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
        {
-           FcChar8 * t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
+           FcChar8 * t;
+           memcpy (&t, ((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1, sizeof (FcChar8 *));
            if (!t)
            {
                strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
-               *(FcChar8 **)((FcChar8 *) (b + 1) + strlen((char *)s) + 1) = (static_strs[bi] + fcstr_ptr);
+               t = static_strs[bi] + fcstr_ptr;
+               memcpy ((FcChar8 *) (b + 1) + strlen((char *)s) + 1, &t, sizeof (FcChar8 *));
                fcstr_ptr += strlen((char *)s) + 1;
-               t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
+               memcpy (&t, ((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1, sizeof (FcChar8 *));
            }
            return t;
        }
@@ -1858,17 +1993,85 @@ FcStrSerialize (int bank, const FcChar8 * s)
 }
 
 static void *
-FcStrUnserialize (FcCache metadata, void *block_ptr)
+FcStrUnserialize (FcCache metadata, void *block_ptr)
 {
-    int bi = FcCacheBankToIndex(metadata.bank);
+    int bi = FcCacheBankToIndex(metadata->bank);
     if (!FcStrEnsureBank(bi))
        return 0;
 
-    FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata.str_count);
+    FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata->str_count);
+    block_ptr = ALIGN (block_ptr, FcChar8);
     static_strs[bi] = (FcChar8 *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
-                        (sizeof (char) * metadata.str_count));
+                        (sizeof (char) * metadata->str_count));
 
     return block_ptr;
 }
 
+/* we don't store these in the FcPattern itself because
+ * we don't want to serialize the directory names */
+
+/* I suppose this should be cleaned upon termination, too... */
+typedef struct _FcPatternDirMapping {
+    const FcPattern    *p;
+    const char *fname;
+} FcPatternDirMapping;
+
+#define PATTERNDIR_HASH_SIZE    31
+static struct patternDirBucket {
+    struct patternDirBucket    *next;
+    FcPatternDirMapping                m;
+} FcPatternDirBuckets[PATTERNDIR_HASH_SIZE];
+
+void
+FcPatternAddFullFname (const FcPattern *p, const char *fname)
+{
+    struct patternDirBucket    *pb;
+
+    /* N.B. FcPatternHash fails, since it's contents-based, not
+     * address-based, and we're in the process of mutating the FcPattern. */
+    for (pb = &FcPatternDirBuckets
+             [((unsigned long)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
+         pb->m.p != p && pb->next; 
+         pb = pb->next)
+        ;
+
+    if (pb->m.p == p)
+    {
+        pb->m.fname = fname;
+        return;
+    }
+
+    pb->next = malloc (sizeof (struct patternDirBucket));
+    if (!pb->next)
+        return;
+    FcMemAlloc (FC_MEM_CACHE, sizeof (struct patternDirBucket));
+
+    pb->next->next = 0;
+    pb->next->m.p = p;
+    pb->next->m.fname = fname;
+}
+
+static const char *
+FcPatternFindFullFname (const FcPattern *p)
+{
+    struct patternDirBucket    *pb;
+
+    for (pb = &FcPatternDirBuckets
+             [((unsigned long)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE]; 
+         pb; pb = pb->next)
+       if (pb->m.p == p)
+           return pb->m.fname;
+
+    return 0;
+}
+
+void
+FcPatternTransferFullFname (const FcPattern *new, const FcPattern *orig)
+{
+    FcChar8 * s;
+    FcPatternGetString (orig, FC_FILE, 0, &s);
+    FcPatternAddFullFname (new, 
+                          (char *)FcStrCopy 
+                          ((FcChar8 *)FcPatternFindFullFname(orig)));
+}