Edit

IABSD.fr/xenocara/lib/fontconfig/src/fcpat.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2010-03-25 21:45:57
    Hash : e248f656
    Message : Update to fontconfig 2.8.0. Tested on a full ports build by naddy@.

  • lib/fontconfig/src/fcpat.c
  • /*
     * Copyright © 2000 Keith Packard
     *
     * Permission to use, copy, modify, distribute, and sell this software and its
     * documentation for any purpose is hereby granted without fee, provided that
     * the above copyright notice appear in all copies and that both that
     * copyright notice and this permission notice appear in supporting
     * documentation, and that the name of Keith Packard not be used in
     * advertising or publicity pertaining to distribution of the software without
     * specific, written prior permission.  Keith Packard makes no
     * representations about the suitability of this software for any purpose.  It
     * is provided "as is" without express or implied warranty.
     *
     * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     * PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include "fcint.h"
    #include "fcftint.h"
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    
    static FcBool
    FcHashOwnsName(const FcChar8 *name);
    
    FcPattern *
    FcPatternCreate (void)
    {
        FcPattern	*p;
    
        p = (FcPattern *) malloc (sizeof (FcPattern));
        if (!p)
    	return 0;
        FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
        p->num = 0;
        p->size = 0;
        p->elts_offset = FcPtrToOffset (p, NULL);
        p->ref = 1;
        return p;
    }
    
    void
    FcValueDestroy (FcValue v)
    {
        switch (v.type) {
        case FcTypeString:
            if (!FcHashOwnsName(v.u.s))
                FcStrFree ((FcChar8 *) v.u.s);
    	break;
        case FcTypeMatrix:
    	FcMatrixFree ((FcMatrix *) v.u.m);
    	break;
        case FcTypeCharSet:
    	FcCharSetDestroy ((FcCharSet *) v.u.c);
    	break;
        case FcTypeLangSet:
    	FcLangSetDestroy ((FcLangSet *) v.u.l);
    	break;
        default:
    	break;
        }
    }
    
    FcValue
    FcValueCanonicalize (const FcValue *v)
    {
        FcValue new;
    
        switch (v->type)
        {
        case FcTypeString:
    	new.u.s = FcValueString(v);
    	new.type = FcTypeString;
    	break;
        case FcTypeCharSet:
    	new.u.c = FcValueCharSet(v);
    	new.type = FcTypeCharSet;
    	break;
        case FcTypeLangSet:
    	new.u.l = FcValueLangSet(v);
    	new.type = FcTypeLangSet;
    	break;
        default:
    	new = *v;
    	break;
        }
        return new;
    }
    
    FcValue
    FcValueSave (FcValue v)
    {
        switch (v.type) {
        case FcTypeString:
    	v.u.s = FcStrStaticName (v.u.s);
    	if (!v.u.s)
    	    v.type = FcTypeVoid;
    	break;
        case FcTypeMatrix:
    	v.u.m = FcMatrixCopy (v.u.m);
    	if (!v.u.m)
    	    v.type = FcTypeVoid;
    	break;
        case FcTypeCharSet:
    	v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
    	if (!v.u.c)
    	    v.type = FcTypeVoid;
    	break;
        case FcTypeLangSet:
    	v.u.l = FcLangSetCopy (v.u.l);
    	if (!v.u.l)
    	    v.type = FcTypeVoid;
    	break;
        default:
    	break;
        }
        return v;
    }
    
    void
    FcValueListDestroy (FcValueListPtr l)
    {
        FcValueListPtr next;
        for (; l; l = next)
        {
    	switch (l->value.type) {
    	case FcTypeString:
                if (!FcHashOwnsName((FcChar8 *)l->value.u.s))
                    FcStrFree ((FcChar8 *)l->value.u.s);
    	    break;
    	case FcTypeMatrix:
    	    FcMatrixFree ((FcMatrix *)l->value.u.m);
    	    break;
    	case FcTypeCharSet:
    	    FcCharSetDestroy 
    		((FcCharSet *) (l->value.u.c));
    	    break;
    	case FcTypeLangSet:
    	    FcLangSetDestroy 
    		((FcLangSet *) (l->value.u.l));
    	    break;
    	default:
    	    break;
    	}
    	next = FcValueListNext(l);
    	FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
    	free(l);
        }
    }
    
    FcBool
    FcValueEqual (FcValue va, FcValue vb)
    {
        if (va.type != vb.type)
        {
    	if (va.type == FcTypeInteger)
    	{
    	    va.type = FcTypeDouble;
    	    va.u.d = va.u.i;
    	}
    	if (vb.type == FcTypeInteger)
    	{
    	    vb.type = FcTypeDouble;
    	    vb.u.d = vb.u.i;
    	}
    	if (va.type != vb.type)
    	    return FcFalse;
        }
        switch (va.type) {
        case FcTypeVoid:
    	return FcTrue;
        case FcTypeInteger:
    	return va.u.i == vb.u.i;
        case FcTypeDouble:
    	return va.u.d == vb.u.d;
        case FcTypeString:
    	return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
        case FcTypeBool:
    	return va.u.b == vb.u.b;
        case FcTypeMatrix:
    	return FcMatrixEqual (va.u.m, vb.u.m);
        case FcTypeCharSet:
    	return FcCharSetEqual (va.u.c, vb.u.c);
        case FcTypeFTFace:
    	return va.u.f == vb.u.f;
        case FcTypeLangSet:
    	return FcLangSetEqual (va.u.l, vb.u.l);
        }
        return FcFalse;
    }
    
    static FcChar32
    FcDoubleHash (double d)
    {
        if (d < 0)
    	d = -d;
        if (d > 0xffffffff)
    	d = 0xffffffff;
        return (FcChar32) d;
    }
    
    FcChar32
    FcStringHash (const FcChar8 *s)
    {
        FcChar8	c;
        FcChar32	h = 0;
        
        if (s)
    	while ((c = *s++))
    	    h = ((h << 1) | (h >> 31)) ^ c;
        return h;
    }
    
    static FcChar32
    FcValueHash (const FcValue *v)
    {
        switch (v->type) {
        case FcTypeVoid:
    	return 0;
        case FcTypeInteger:
    	return (FcChar32) v->u.i;
        case FcTypeDouble:
    	return FcDoubleHash (v->u.d);
        case FcTypeString:
    	return FcStringHash (FcValueString(v));
        case FcTypeBool:
    	return (FcChar32) v->u.b;
        case FcTypeMatrix:
    	return (FcDoubleHash (v->u.m->xx) ^ 
    		FcDoubleHash (v->u.m->xy) ^ 
    		FcDoubleHash (v->u.m->yx) ^ 
    		FcDoubleHash (v->u.m->yy));
        case FcTypeCharSet:
    	return (FcChar32) FcValueCharSet(v)->num;
        case FcTypeFTFace:
    	return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
    	       FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
        case FcTypeLangSet:
    	return FcLangSetHash (FcValueLangSet(v));
        }
        return FcFalse;
    }
    
    static FcBool
    FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
    {
        if (la == lb)
    	return FcTrue;
    
        while (la && lb)
        {
    	if (!FcValueEqual (la->value, lb->value))
    	    return FcFalse;
    	la = FcValueListNext(la);
    	lb = FcValueListNext(lb);
        }
        if (la || lb)
    	return FcFalse;
        return FcTrue;
    }
    
    static FcChar32
    FcValueListHash (FcValueListPtr l)
    {
        FcChar32	hash = 0;
        
        for (; l; l = FcValueListNext(l))
        {
    	hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value);
        }
        return hash;
    }
    
    void
    FcPatternDestroy (FcPattern *p)
    {
        int		    i;
        FcPatternElt    *elts;
        
        if (p->ref == FC_REF_CONSTANT)
        {
    	FcCacheObjectDereference (p);
    	return;
        }
    	
        if (--p->ref > 0)
    	return;
    
        elts = FcPatternElts (p);
        for (i = 0; i < p->num; i++)
    	FcValueListDestroy (FcPatternEltValues(&elts[i]));
    
        FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
        free (elts);
        FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
        free (p);
    }
    
    static int
    FcPatternObjectPosition (const FcPattern *p, FcObject object)
    {
        int	    low, high, mid, c;
        FcPatternElt    *elts = FcPatternElts(p);
    
        low = 0;
        high = p->num - 1;
        c = 1;
        mid = 0;
        while (low <= high)
        {
    	mid = (low + high) >> 1;
    	c = elts[mid].object - object;
    	if (c == 0)
    	    return mid;
    	if (c < 0)
    	    low = mid + 1;
    	else
    	    high = mid - 1;
        }
        if (c < 0)
    	mid++;
        return -(mid + 1);
    }
    
    FcPatternElt *
    FcPatternObjectFindElt (const FcPattern *p, FcObject object)
    {
        int	    i = FcPatternObjectPosition (p, object);
        if (i < 0)
    	return 0;
        return &FcPatternElts(p)[i];
    }
    
    FcPatternElt *
    FcPatternObjectInsertElt (FcPattern *p, FcObject object)
    {
        int		    i;
        FcPatternElt   *e;
        
        i = FcPatternObjectPosition (p, object);
        if (i < 0)
        {
    	i = -i - 1;
        
    	/* reallocate array */
    	if (p->num + 1 >= p->size)
    	{
    	    int s = p->size + 16;
    	    if (p->size)
    	    {
    		FcPatternElt *e0 = FcPatternElts(p);
    		e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
    		if (!e) /* maybe it was mmapped */
    		{
    		    e = malloc(s * sizeof (FcPatternElt));
    		    if (e)
    			memcpy(e, e0, p->num * sizeof (FcPatternElt));
    		}
    	    }
    	    else
    		e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
    	    if (!e)
    		return FcFalse;
    	    p->elts_offset = FcPtrToOffset (p, e);
    	    if (p->size)
    		FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
    	    FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
    	    while (p->size < s)
    	    {
    		e[p->size].object = 0;
    		e[p->size].values = NULL;
    		p->size++;
    	    }
    	}
    	
    	e = FcPatternElts(p);
    	/* move elts up */
    	memmove (e + i + 1,
    		 e + i,
    		 sizeof (FcPatternElt) *
    		 (p->num - i));
    		 
    	/* bump count */
    	p->num++;
    	
    	e[i].object = object;
    	e[i].values = NULL;
        }
        
        return FcPatternElts(p) + i;
    }
    
    FcBool
    FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
    {
        int	i;
        FcPatternElt   *pae, *pbe;
    
        if (pa == pb)
    	return FcTrue;
    
        if (pa->num != pb->num)
    	return FcFalse;
        pae = FcPatternElts(pa);
        pbe = FcPatternElts(pb);
        for (i = 0; i < pa->num; i++)
        {
    	if (pae[i].object != pbe[i].object)
    	    return FcFalse;
    	if (!FcValueListEqual (FcPatternEltValues(&pae[i]),
    			       FcPatternEltValues(&pbe[i])))
    	    return FcFalse;
        }
        return FcTrue;
    }
    
    FcChar32
    FcPatternHash (const FcPattern *p)
    {
        int		i;
        FcChar32	h = 0;
        FcPatternElt    *pe = FcPatternElts(p);
    
        for (i = 0; i < p->num; i++)
        {
    	h = (((h << 1) | (h >> 31)) ^ 
    	     pe[i].object ^
    	     FcValueListHash (FcPatternEltValues(&pe[i])));
        }
        return h;
    }
    
    FcBool
    FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
    {
        FcPatternElt    *ea, *eb;
        int		    i;
        
        for (i = 0; i < os->nobject; i++)
        {
    	FcObject    object = FcObjectFromName (os->objects[i]);
    	ea = FcPatternObjectFindElt (pai, object);
    	eb = FcPatternObjectFindElt (pbi, object);
    	if (ea)
    	{
    	    if (!eb)
    		return FcFalse;
    	    if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
    		return FcFalse;
    	}
    	else
    	{
    	    if (eb)
    		return FcFalse;
    	}
        }
        return FcTrue;
    }
    
    FcBool
    FcPatternObjectAddWithBinding  (FcPattern	*p,
    				FcObject	object,
    				FcValue		value,
    				FcValueBinding  binding,
    				FcBool		append)
    {
        FcPatternElt   *e;
        FcValueListPtr new, *prev;
    
        if (p->ref == FC_REF_CONSTANT)
    	goto bail0;
    
        new = malloc (sizeof (FcValueList));
        if (!new)
    	goto bail0;
    
        memset(new, 0, sizeof (FcValueList));
        FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
        value = FcValueSave (value);
        if (value.type == FcTypeVoid)
    	goto bail1;
    
        /*
         * Make sure the stored type is valid for built-in objects
         */
        if (!FcObjectValidType (object, value.type))
        {
    	if (FcDebug() & FC_DBG_OBJTYPES)
    	{
    	    printf ("FcPattern object %s does not accept value ",
    		    FcObjectName (object));
    	    FcValuePrint (value);
    	}
    	goto bail1;
        }
    
        new->value = value;
        new->binding = binding;
        new->next = NULL;
        
        e = FcPatternObjectInsertElt (p, object);
        if (!e)
    	goto bail2;
        
        if (append)
        {
    	for (prev = &e->values; *prev; prev = &(*prev)->next)
    	    ;
    	*prev = new;
        }
        else
        {
    	new->next = e->values;
    	e->values = new;
        }
        
        return FcTrue;
    
    bail2:    
        FcValueDestroy (value);
    bail1:
        FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
        free (new);
    bail0:
        return FcFalse;
    }
    
    FcBool
    FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
    {
        return FcPatternObjectAddWithBinding (p, object,
    					  value, FcValueBindingStrong, append);
    }
    
    FcBool
    FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
    {
        return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
    					  value, FcValueBindingStrong, append);
    }
    
    FcBool
    FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
    {
        return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
    					  value, FcValueBindingWeak, append);
    }
    
    FcBool
    FcPatternObjectDel (FcPattern *p, FcObject object)
    {
        FcPatternElt   *e;
    
        e = FcPatternObjectFindElt (p, object);
        if (!e)
    	return FcFalse;
    
        /* destroy value */
        FcValueListDestroy (e->values);
        
        /* shuffle existing ones down */
        memmove (e, e+1, 
    	     (FcPatternElts(p) + p->num - (e + 1)) * 
    	     sizeof (FcPatternElt));
        p->num--;
        e = FcPatternElts(p) + p->num;
        e->object = 0;
        e->values = NULL;
        return FcTrue;
    }
    
    FcBool
    FcPatternDel (FcPattern *p, const char *object)
    {
        return FcPatternObjectDel (p, FcObjectFromName (object));
    }
        
    FcBool
    FcPatternRemove (FcPattern *p, const char *object, int id)
    {
        FcPatternElt    *e;
        FcValueListPtr  *prev, l;
    
        e = FcPatternObjectFindElt (p, FcObjectFromName (object));
        if (!e)
    	return FcFalse;
        for (prev = &e->values; (l = *prev); prev = &l->next)
        {
    	if (!id)
    	{
    	    *prev = l->next;
    	    l->next = NULL;
    	    FcValueListDestroy (l);
    	    if (!e->values)
    		FcPatternDel (p, object);
    	    return FcTrue;
    	}
    	id--;
        }
        return FcFalse;
    }
    
    FcBool
    FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
    {
        FcValue	v;
    
        v.type = FcTypeInteger;
        v.u.i = i;
        return FcPatternObjectAdd (p, object, v, FcTrue);
    }
    
    FcBool
    FcPatternAddInteger (FcPattern *p, const char *object, int i)
    {
        return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
    }
    
    FcBool
    FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
    {
        FcValue	v;
    
        v.type = FcTypeDouble;
        v.u.d = d;
        return FcPatternObjectAdd (p, object, v, FcTrue);
    }
    
    
    FcBool
    FcPatternAddDouble (FcPattern *p, const char *object, double d)
    {
        return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
    }
    
    FcBool
    FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
    {
        FcValue	v;
    
        if (!s)
        {
    	v.type = FcTypeVoid;
    	v.u.s = 0;
    	return FcPatternObjectAdd (p, object, v, FcTrue);
        }
    
        v.type = FcTypeString;
        v.u.s = FcStrStaticName(s);
        return FcPatternObjectAdd (p, object, v, FcTrue);
    }
    
    FcBool
    FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
    {
        return FcPatternObjectAddString (p, FcObjectFromName (object), s);
    }
    
    FcBool
    FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
    {
        FcValue	v;
    
        v.type = FcTypeMatrix;
        v.u.m = s;
        return FcPatternAdd (p, object, v, FcTrue);
    }
    
    
    FcBool
    FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
    {
        FcValue	v;
    
        v.type = FcTypeBool;
        v.u.b = b;
        return FcPatternObjectAdd (p, object, v, FcTrue);
    }
    
    FcBool
    FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
    {
        return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
    }
    
    FcBool
    FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
    {
        FcValue	v;
    
        v.type = FcTypeCharSet;
        v.u.c = (FcCharSet *)c;
        return FcPatternAdd (p, object, v, FcTrue);
    }
    
    FcBool
    FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
    {
        FcValue	v;
    
        v.type = FcTypeFTFace;
        v.u.f = (void *) f;
        return FcPatternAdd (p, object, v, FcTrue);
    }
    
    FcBool
    FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
    {
        FcValue	v;
    
        v.type = FcTypeLangSet;
        v.u.l = (FcLangSet *)ls;
        return FcPatternAdd (p, object, v, FcTrue);
    }
    
    FcResult
    FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
    {
        FcPatternElt   *e;
        FcValueListPtr l;
    
        e = FcPatternObjectFindElt (p, object);
        if (!e)
    	return FcResultNoMatch;
        for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
        {
    	if (!id)
    	{
    	    *v = FcValueCanonicalize(&l->value);
    	    return FcResultMatch;
    	}
    	id--;
        }
        return FcResultNoId;
    }
    
    FcResult
    FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
    {
        return FcPatternObjectGet (p, FcObjectFromName (object), id, v);
    }
    
    FcResult
    FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
    {
        FcValue	v;
        FcResult	r;
    
        r = FcPatternObjectGet (p, object, id, &v);
        if (r != FcResultMatch)
    	return r;
        switch (v.type) {
        case FcTypeDouble:
    	*i = (int) v.u.d;
    	break;
        case FcTypeInteger:
    	*i = v.u.i;
    	break;
        default:
            return FcResultTypeMismatch;
        }
        return FcResultMatch;
    }
    
    FcResult
    FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
    {
        return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
    }
        
        
    FcResult
    FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
    {
        FcValue	v;
        FcResult	r;
    
        r = FcPatternObjectGet (p, object, id, &v);
        if (r != FcResultMatch)
    	return r;
        switch (v.type) {
        case FcTypeDouble:
    	*d = v.u.d;
    	break;
        case FcTypeInteger:
    	*d = (double) v.u.i;
    	break;
        default:
            return FcResultTypeMismatch;
        }
        return FcResultMatch;
    }
    
    FcResult
    FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
    {
        return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
    }
    
    FcResult
    FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
    {
        FcValue	v;
        FcResult	r;
    
        r = FcPatternObjectGet (p, object, id, &v);
        if (r != FcResultMatch)
    	return r;
        if (v.type != FcTypeString)
            return FcResultTypeMismatch;
    
        *s = (FcChar8 *) v.u.s;
        return FcResultMatch;
    }
    
    FcResult
    FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
    {
        return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
    }
        
    FcResult
    FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
    {
        FcValue	v;
        FcResult	r;
    
        r = FcPatternGet (p, object, id, &v);
        if (r != FcResultMatch)
    	return r;
        if (v.type != FcTypeMatrix)
            return FcResultTypeMismatch;
        *m = (FcMatrix *)v.u.m;
        return FcResultMatch;
    }
    
    
    FcResult
    FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
    {
        FcValue	v;
        FcResult	r;
    
        r = FcPatternGet (p, object, id, &v);
        if (r != FcResultMatch)
    	return r;
        if (v.type != FcTypeBool)
            return FcResultTypeMismatch;
        *b = v.u.b;
        return FcResultMatch;
    }
    
    FcResult
    FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
    {
        FcValue	v;
        FcResult	r;
    
        r = FcPatternGet (p, object, id, &v);
        if (r != FcResultMatch)
    	return r;
        if (v.type != FcTypeCharSet)
            return FcResultTypeMismatch;
        *c = (FcCharSet *)v.u.c;
        return FcResultMatch;
    }
    
    FcResult
    FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
    {
        FcValue	v;
        FcResult	r;
    
        r = FcPatternGet (p, object, id, &v);
        if (r != FcResultMatch)
    	return r;
        if (v.type != FcTypeFTFace)
    	return FcResultTypeMismatch;
        *f = (FT_Face) v.u.f;
        return FcResultMatch;
    }
    
    FcResult
    FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
    {
        FcValue	v;
        FcResult	r;
    
        r = FcPatternGet (p, object, id, &v);
        if (r != FcResultMatch)
    	return r;
        if (v.type != FcTypeLangSet)
            return FcResultTypeMismatch;
        *ls = (FcLangSet *)v.u.l;
        return FcResultMatch;
    }
    
    FcPattern *
    FcPatternDuplicate (const FcPattern *orig)
    {
        FcPattern	    *new;
        FcPatternElt    *e;
        int		    i;
        FcValueListPtr  l;
    
        new = FcPatternCreate ();
        if (!new)
    	goto bail0;
    
        e = FcPatternElts(orig);
    
        for (i = 0; i < orig->num; i++)
        {
    	for (l = FcPatternEltValues(e + i); l; l = FcValueListNext(l))
    	{
    	    if (!FcPatternObjectAddWithBinding (new, e[i].object,
    						FcValueCanonicalize(&l->value),
    						l->binding,
    						FcTrue))
    		goto bail1;
    	    
    	}
        }
    
        return new;
    
    bail1:
        FcPatternDestroy (new);
    bail0:
        return 0;
    }
    
    void
    FcPatternReference (FcPattern *p)
    {
        if (p->ref != FC_REF_CONSTANT)
    	p->ref++;
        else
    	FcCacheObjectReference (p);
    }
    
    FcPattern *
    FcPatternVaBuild (FcPattern *p, va_list va)
    {
        FcPattern	*ret;
        
        FcPatternVapBuild (ret, p, va);
        return ret;
    }
    
    FcPattern *
    FcPatternBuild (FcPattern *p, ...)
    {
        va_list	va;
        
        va_start (va, p);
        FcPatternVapBuild (p, p, va);
        va_end (va);
        return p;
    }
    
    /*
     * Add all of the elements in 's' to 'p'
     */
    FcBool
    FcPatternAppend (FcPattern *p, FcPattern *s)
    {
        int		    i;
        FcPatternElt    *e;
        FcValueListPtr  v;
        
        for (i = 0; i < s->num; i++)
        {
    	e = FcPatternElts(s)+i;
    	for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
    	{
    	    if (!FcPatternObjectAddWithBinding (p, e->object,
    						FcValueCanonicalize(&v->value), 
    						v->binding, FcTrue))
    		return FcFalse;
    	}
        }
        return FcTrue;
    }
    
    FcPattern *
    FcPatternFilter (FcPattern *p, const FcObjectSet *os)
    {
        int		    i;
        FcPattern	    *ret;
        FcPatternElt    *e;
        FcValueListPtr  v;
    
        if (!os)
    	return FcPatternDuplicate (p);
    
        ret = FcPatternCreate ();
        if (!ret)
    	return NULL;
    
        for (i = 0; i < os->nobject; i++)
        {
    	FcObject object = FcObjectFromName (os->objects[i]);
    	e = FcPatternObjectFindElt (p, object);
    	if (e)
    	{
    	    for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
    	    {
    		if (!FcPatternObjectAddWithBinding (ret, e->object,
    						    FcValueCanonicalize(&v->value),
    						    v->binding, FcTrue))
    		    goto bail0;
    	    }
    	}
        }
        return ret;
    
    bail0:
        FcPatternDestroy (ret);
        return NULL;
    }
    
    #define OBJECT_HASH_SIZE    31
    static struct objectBucket {
        struct objectBucket	*next;
        FcChar32		hash;
    } *FcObjectBuckets[OBJECT_HASH_SIZE];
    
    static FcBool
    FcHashOwnsName (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 && ((char *)name == (char *) (b + 1)))
                return FcTrue;
        return FcFalse;
    }
    
    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), (char *)name);
        *p = b;
        return (FcChar8 *) (b + 1);
    }
    
    static void
    FcStrStaticNameFini (void)
    {
        int i, size;
        struct objectBucket *b, *next;
        char *name;
    
        for (i = 0; i < OBJECT_HASH_SIZE; i++)
        {
    	for (b = FcObjectBuckets[i]; b; b = next)
    	{
    	    next = b->next;
    	    name = (char *) (b + 1);
    	    size = sizeof (struct objectBucket) + strlen (name) + 1;
    	    FcMemFree (FC_MEM_STATICSTR, size + sizeof (int));
    	    free (b);
    	}
    	FcObjectBuckets[i] = 0;
        }
    }
    
    void
    FcPatternFini (void)
    {
        FcStrStaticNameFini ();
        FcObjectFini ();
    }
    
    FcBool
    FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
    {
        int	i;
        FcPatternElt    *elts = FcPatternElts(pat);
        
        if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
    	return FcFalse;
        if (!FcSerializeAlloc (serialize, elts, pat->num * sizeof (FcPatternElt)))
    	return FcFalse;
        for (i = 0; i < pat->num; i++)
    	if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
    	    return FcFalse;
        return FcTrue;
    }
    
    FcPattern *
    FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
    {
        FcPattern	    *pat_serialized;
        FcPatternElt    *elts = FcPatternElts (pat);
        FcPatternElt    *elts_serialized;
        FcValueList	    *values_serialized;
        int		    i;
    
        pat_serialized = FcSerializePtr (serialize, pat);
        if (!pat_serialized)
    	return NULL;
        *pat_serialized = *pat;
        pat_serialized->size = pat->num;
        pat_serialized->ref = FC_REF_CONSTANT;
        
        elts_serialized = FcSerializePtr (serialize, elts);
        if (!elts_serialized)
    	return NULL;
        
        pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
    						 elts_serialized);
    
        for (i = 0; i < pat->num; i++)
        {
    	values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
    	if (!values_serialized)
    	    return NULL;
    	elts_serialized[i].object = elts[i].object;
    	elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i], 
    							  values_serialized,
    							  FcValueList);
        }
        if (FcDebug() & FC_DBG_CACHEV) {
    	printf ("Raw pattern:\n");
    	FcPatternPrint (pat);
    	printf ("Serialized pattern:\n");
    	FcPatternPrint (pat_serialized);
    	printf ("\n");
        }
        return pat_serialized;
    }
    
    FcBool
    FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
    {
        while (vl)
        {
    	if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
    	    return FcFalse;
    	switch (vl->value.type) {
    	case FcTypeString:
    	    if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
    		return FcFalse;
    	    break;
    	case FcTypeCharSet:
    	    if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
    		return FcFalse;
    	    break;
    	case FcTypeLangSet:
    	    if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
    		return FcFalse;
    	    break;
    	default:
    	    break;
    	}
    	vl = vl->next;
        }
        return FcTrue;
    }
    
    FcValueList *
    FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
    {
        FcValueList	*vl_serialized;
        FcChar8	*s_serialized;
        FcCharSet	*c_serialized;
        FcLangSet	*l_serialized;
        FcValueList	*head_serialized = NULL;
        FcValueList	*prev_serialized = NULL;
    
        while (vl)
        {
    	vl_serialized = FcSerializePtr (serialize, vl);
    	if (!vl_serialized)
    	    return NULL;
        
    	if (prev_serialized)
    	    prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
    							  vl_serialized,
    							  FcValueList);
    	else
    	    head_serialized = vl_serialized;
    	
    	vl_serialized->next = NULL;
    	vl_serialized->value.type = vl->value.type;
    	switch (vl->value.type) {
    	case FcTypeInteger:
    	    vl_serialized->value.u.i = vl->value.u.i;
    	    break;
    	case FcTypeDouble:
    	    vl_serialized->value.u.d = vl->value.u.d;
    	    break;
    	case FcTypeString:
    	    s_serialized = FcStrSerialize (serialize, vl->value.u.s);
    	    if (!s_serialized)
    		return NULL;
    	    vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
    							     s_serialized,
    							     FcChar8);
    	    break;
    	case FcTypeBool:
    	    vl_serialized->value.u.b = vl->value.u.b;
    	    break;
    	case FcTypeMatrix:
    	    /* can't happen */
    	    break;
    	case FcTypeCharSet:
    	    c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
    	    if (!c_serialized)
    		return NULL;
    	    vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
    							     c_serialized,
    							     FcCharSet);
    	    break;
    	case FcTypeFTFace:
    	    /* can't happen */
    	    break;
    	case FcTypeLangSet:
    	    l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
    	    if (!l_serialized)
    		return NULL;
    	    vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
    							     l_serialized,
    							     FcLangSet);
    	    break;
    	default:
    	    break;
    	}
    	prev_serialized = vl_serialized;
    	vl = vl->next;
        }
        return head_serialized;
    }
    #define __fcpat__
    #include "fcaliastail.h"
    #include "fcftaliastail.h"
    #undef __fcpat__