]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcpat.c
Copy the full pathname whenever duplicating an FcPattern; otherwise,
[fontconfig.git] / src / fcpat.c
index e3f244aa8a39419d39164aa5bcf76da2a7ecf25a..b7f52793c6e63a0515038a53660e4a0776c037b8 100644 (file)
@@ -34,6 +34,8 @@ static int fcpatternelt_ptr, fcpatternelt_count;
 static FcValueList ** fcvaluelists = 0;
 static int fcvaluelist_bank_count = 0, fcvaluelist_ptr, fcvaluelist_count;
 
+static const char *
+FcPatternFindFullFname (const FcPattern *p);
 static FcPatternEltPtr
 FcPatternEltPtrCreateDynamic (FcPatternElt * e);
 
@@ -295,6 +297,9 @@ FcPatternDestroy (FcPattern *p)
 {
     int                    i;
     
+    if (FcPatternFindFullFname (p))
+       FcPatternAddFullFname (p, 0);
+
     if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
        return;
 
@@ -331,7 +336,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 +582,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 +652,10 @@ FcPatternFreeze (FcPattern *p)
        if (!FcValueListPtrU((FcPatternEltU(p->elts)+i)->values))
            goto bail;
     }
+
+    if (FcPatternFindElt (p, FC_FILE))
+       FcPatternTransferFullFname (b, p);
+
     /*
      * Freeze base
      */
@@ -792,7 +804,7 @@ FcPatternHash (const FcPattern *p)
     for (i = 0; i < p->num; i++)
     {
        h = (((h << 1) | (h >> 31)) ^ 
-            FcStringHash ((const FcChar8 *) ((FcPatternEltU(p->elts)+i)->object)) ^
+            FcStringHash ((FcChar8 *)FcObjectPtrU ((FcPatternEltU(p->elts)+i)->object)) ^
             FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
     }
     return h;
@@ -1115,6 +1127,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,8 +1263,16 @@ 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;
+
+       if (!strcmp ((char *)FcObjectPtrU((e + i)->object), FC_FILE))
+       {
+           FcChar8 * s;
+           FcPatternGetString (orig, FC_FILE, 0, &s);
+           FcPatternAddFullFname (new, FcPatternFindFullFname(orig));
+       }
     }
 
     return new;
@@ -1280,34 +1336,33 @@ FcPatternAppend (FcPattern *p, FcPattern *s)
 }
 
 #define OBJECT_HASH_SIZE    31
-struct objectBucket {
+static struct objectBucket {
     struct objectBucket        *next;
     FcChar32           hash;
-};
-static struct objectBucket *FcObjectBuckets[OBJECT_HASH_SIZE];
-
-const char *
-FcStrStaticName (const char *name)
-{
-    FcChar32            hash = FcStringHash ((const FcChar8 *) name);
-    struct objectBucket **p;
-    struct objectBucket *b;
-    int                 size;
-
-    for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)
-)
-        if (b->hash == hash && !strcmp (name, (char *) (b + 1)))
-            return (char *) (b + 1);
-    size = sizeof (struct objectBucket) + strlen (name) + 1;
-    b = malloc (size);
-    FcMemAlloc (FC_MEM_STATICSTR, size);
+} *FcObjectBuckets[OBJECT_HASH_SIZE];
+
+const FcChar8 *
+FcStrStaticName (const FcChar8 *name)
+{
+    FcChar32           hash = FcStringHash (name);
+    struct objectBucket        **p;
+    struct objectBucket        *b;
+    int                        size;
+
+    for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
+       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 + 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;
     b->hash = hash;
-    strcpy ((char *) (b + 1), name);
+    strcpy ((char *) (b + 1), (char *)name);
     *p = b;
-    return (char *) (b + 1);
+    return (FcChar8 *) (b + 1);
 }
 
 static void
@@ -1370,11 +1425,11 @@ FcPatternEltPtrCreateStatic (int bank, int i)
 static void
 FcStrNewBank (void);
 static int
-FcStrNeededBytes (const char * s);
+FcStrNeededBytes (const FcChar8 * s);
 static void *
 FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
-static const char *
-FcStrSerialize (int bank, const char * s);
+static const FcChar8 *
+FcStrSerialize (int bank, const FcChar8 * s);
 static void *
 FcStrUnserialize (FcCache metadata, void *block_ptr);
 
@@ -1669,10 +1724,10 @@ FcValueListSerialize(int bank, FcValueList *pi)
     case FcTypeString:
        if (v->u.s)
        {
-           const char * s = FcStrSerialize(bank, v->u.s);
+           const FcChar8 * s = FcStrSerialize(bank, v->u.s);
            if (!s)
                return FcValueListPtrCreateDynamic(pi);
-           v->u.s_off = s - (const char *)v;
+           v->u.s_off = s - (const FcChar8 *)v;
            v->type |= FC_STORAGE_STATIC;
        }
        break;
@@ -1743,7 +1798,7 @@ FcValueListPtrCreateDynamic(FcValueList * p)
     return r;
 }
 
-static char ** static_strs;
+static FcChar8 ** static_strs;
 static int static_str_bank_count = 0, fcstr_ptr, fcstr_count;
 
 static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE];
@@ -1772,7 +1827,7 @@ FcStrNewBank (void)
 }
 
 static int
-FcStrNeededBytes (const char * s)
+FcStrNeededBytes (const FcChar8 * s)
 {
     FcChar32            hash = FcStringHash ((const FcChar8 *) s);
     struct objectBucket **p;
@@ -1780,27 +1835,27 @@ FcStrNeededBytes (const char * s)
     int                 size;
 
     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
-        if (b->hash == hash && !strcmp (s, (char *) (b + 1)))
+        if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
             return 0;
-    size = sizeof (struct objectBucket) + strlen (s) + 1 + sizeof(char *);
+    size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *);
     b = malloc (size);
     FcMemAlloc (FC_MEM_STATICSTR, size);
     if (!b)
         return -1;
     b->next = 0;
     b->hash = hash;
-    strcpy ((char *) (b + 1), s);
-    *(char **)((char *) (b + 1) + strlen(s) + 1) = 0;
+    strcpy ((char *) (b + 1), (char *)s);
+    *(char **)((char *) (b + 1) + strlen((char *)s) + 1) = 0;
     *p = b;
 
-    fcstr_count += strlen(s) + 1;
-    return strlen(s) + 1;
+    fcstr_count += strlen((char *)s) + 1;
+    return strlen((char *)s) + 1;
 }
 
 static FcBool
 FcStrEnsureBank (int bi)
 {
-    char ** ss;
+    FcChar8 ** ss;
 
     if (!static_strs || static_str_bank_count <= bi)
     {
@@ -1827,7 +1882,7 @@ FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
        return 0;
 
     FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
-    static_strs[bi] = (char *)block_ptr;
+    static_strs[bi] = (FcChar8 *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
     metadata->str_count = fcstr_count;
     fcstr_ptr = 0;
@@ -1835,8 +1890,8 @@ FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
     return block_ptr;
 }
 
-static const char *
-FcStrSerialize (int bank, const char * s)
+static const FcChar8 *
+FcStrSerialize (int bank, const FcChar8 * s)
 {
     FcChar32            hash = FcStringHash ((const FcChar8 *) s);
     struct objectBucket **p;
@@ -1844,15 +1899,15 @@ FcStrSerialize (int bank, const char * s)
     int bi = FcCacheBankToIndex(bank);
 
     for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
-        if (b->hash == hash && !strcmp (s, (char *) (b + 1)))
+        if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
        {
-           char * t = *(char **)(((char *)(b + 1)) + strlen (s) + 1);
+           FcChar8 * t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
            if (!t)
            {
-               strcpy(static_strs[bi] + fcstr_ptr, s);
-               *(char **)((char *) (b + 1) + strlen(s) + 1) = (static_strs[bi] + fcstr_ptr);
-               fcstr_ptr += strlen(s) + 1;
-               t = *(char **)(((char *)(b + 1)) + strlen (s) + 1);
+               strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
+               *(FcChar8 **)((FcChar8 *) (b + 1) + strlen((char *)s) + 1) = (static_strs[bi] + fcstr_ptr);
+               fcstr_ptr += strlen((char *)s) + 1;
+               t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
            }
            return t;
        }
@@ -1867,10 +1922,75 @@ FcStrUnserialize (FcCache metadata, void *block_ptr)
        return 0;
 
     FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata.str_count);
-    static_strs[bi] = (char *)block_ptr;
+    static_strs[bi] = (FcChar8 *)block_ptr;
     block_ptr = (void *)((char *)block_ptr + 
                         (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, 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
+             [((int)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
+             [((int)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, FcPatternFindFullFname(orig));
+}