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