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