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