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