]> git.wh0rd.org - fontconfig.git/blame - src/fcpat.c
Inline FcDebug invocations and only initialize once, in FcInit*. Improve
[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
cd2ec1a9
PL
875 FcValueListPtrU(new)->value = value;
876 FcValueListPtrU(new)->binding = binding;
877 FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
24330d27 878
e9be9cd1 879 e = FcPatternInsertElt (p, object);
24330d27
KP
880 if (!e)
881 goto bail2;
882
883 if (append)
884 {
cd2ec1a9
PL
885 for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
886 ;
24330d27
KP
887 *prev = new;
888 }
889 else
890 {
cd2ec1a9 891 FcValueListPtrU(new)->next = e->values;
24330d27
KP
892 e->values = new;
893 }
894
895 return FcTrue;
896
897bail2:
898 switch (value.type) {
899 case FcTypeString:
4262e0b3 900 FcStrFree ((FcChar8 *) value.u.s);
24330d27
KP
901 break;
902 case FcTypeMatrix:
4262e0b3 903 FcMatrixFree ((FcMatrix *) value.u.m);
24330d27
KP
904 break;
905 case FcTypeCharSet:
4262e0b3 906 FcCharSetDestroy ((FcCharSet *) value.u.c);
24330d27 907 break;
d8d73958 908 case FcTypeLangSet:
4262e0b3 909 FcLangSetDestroy ((FcLangSet *) value.u.l);
d8d73958 910 break;
24330d27
KP
911 default:
912 break;
913 }
914bail1:
915 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
cd2ec1a9 916 free (FcValueListPtrU(new));
24330d27
KP
917bail0:
918 return FcFalse;
919}
920
82f4243f
KP
921FcBool
922FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
923{
924 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
925}
926
927FcBool
928FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
929{
930 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
931}
932
24330d27
KP
933FcBool
934FcPatternDel (FcPattern *p, const char *object)
935{
936 FcPatternElt *e;
24330d27 937
e9be9cd1 938 e = FcPatternFindElt (p, object);
24330d27
KP
939 if (!e)
940 return FcFalse;
941
24330d27
KP
942 /* destroy value */
943 FcValueListDestroy (e->values);
944
945 /* shuffle existing ones down */
cd2ec1a9
PL
946 memmove (e, e+1,
947 (FcPatternEltU(p->elts) + p->num - (e + 1)) *
948 sizeof (FcPatternElt));
24330d27 949 p->num--;
0fa680f0 950 (FcPatternEltU(p->elts)+p->num)->object = 0;
cd2ec1a9 951 (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
24330d27
KP
952 return FcTrue;
953}
954
4f27c1c0
KP
955FcBool
956FcPatternRemove (FcPattern *p, const char *object, int id)
957{
cd2ec1a9
PL
958 FcPatternElt *e;
959 FcValueListPtr *prev, l;
4f27c1c0
KP
960
961 e = FcPatternFindElt (p, object);
962 if (!e)
963 return FcFalse;
cd2ec1a9
PL
964 for (prev = &e->values;
965 FcValueListPtrU(l = *prev);
966 prev = &FcValueListPtrU(l)->next)
4f27c1c0
KP
967 {
968 if (!id)
969 {
cd2ec1a9
PL
970 *prev = FcValueListPtrU(l)->next;
971 FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
4f27c1c0 972 FcValueListDestroy (l);
cd2ec1a9 973 if (!FcValueListPtrU(e->values))
4f27c1c0
KP
974 FcPatternDel (p, object);
975 return FcTrue;
976 }
977 id--;
978 }
979 return FcFalse;
980}
981
24330d27
KP
982FcBool
983FcPatternAddInteger (FcPattern *p, const char *object, int i)
984{
985 FcValue v;
986
987 v.type = FcTypeInteger;
988 v.u.i = i;
989 return FcPatternAdd (p, object, v, FcTrue);
990}
991
992FcBool
993FcPatternAddDouble (FcPattern *p, const char *object, double d)
994{
995 FcValue v;
996
997 v.type = FcTypeDouble;
998 v.u.d = d;
999 return FcPatternAdd (p, object, v, FcTrue);
1000}
1001
1002
1003FcBool
ccb3e93b 1004FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
24330d27
KP
1005{
1006 FcValue v;
1007
1008 v.type = FcTypeString;
7f37423d 1009 v.u.s = FcStrStaticName(s);
24330d27
KP
1010 return FcPatternAdd (p, object, v, FcTrue);
1011}
1012
1013FcBool
1014FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
1015{
1016 FcValue v;
1017
1018 v.type = FcTypeMatrix;
4262e0b3 1019 v.u.m = s;
24330d27
KP
1020 return FcPatternAdd (p, object, v, FcTrue);
1021}
1022
1023
1024FcBool
1025FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
1026{
1027 FcValue v;
1028
1029 v.type = FcTypeBool;
1030 v.u.b = b;
1031 return FcPatternAdd (p, object, v, FcTrue);
1032}
1033
1034FcBool
1035FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
1036{
1037 FcValue v;
1038
1039 v.type = FcTypeCharSet;
4262e0b3 1040 v.u.c = (FcCharSet *)c;
24330d27
KP
1041 return FcPatternAdd (p, object, v, FcTrue);
1042}
1043
be094850
KP
1044FcBool
1045FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
1046{
1047 FcValue v;
1048
1049 v.type = FcTypeFTFace;
1050 v.u.f = (void *) f;
1051 return FcPatternAdd (p, object, v, FcTrue);
1052}
1053
d8d73958
KP
1054FcBool
1055FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1056{
1057 FcValue v;
1058
1059 v.type = FcTypeLangSet;
4262e0b3 1060 v.u.l = (FcLangSet *)ls;
d8d73958
KP
1061 return FcPatternAdd (p, object, v, FcTrue);
1062}
1063
24330d27 1064FcResult
bff80114 1065FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
24330d27
KP
1066{
1067 FcPatternElt *e;
cd2ec1a9 1068 FcValueListPtr l;
24330d27 1069
e9be9cd1 1070 e = FcPatternFindElt (p, object);
24330d27
KP
1071 if (!e)
1072 return FcResultNoMatch;
cd2ec1a9 1073 for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
24330d27
KP
1074 {
1075 if (!id)
1076 {
4262e0b3 1077 *v = FcValueCanonicalize(&FcValueListPtrU(l)->value);
24330d27
KP
1078 return FcResultMatch;
1079 }
1080 id--;
1081 }
1082 return FcResultNoId;
1083}
1084
1085FcResult
bff80114 1086FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
24330d27
KP
1087{
1088 FcValue v;
1089 FcResult r;
1090
1091 r = FcPatternGet (p, object, id, &v);
1092 if (r != FcResultMatch)
1093 return r;
1094 switch (v.type) {
1095 case FcTypeDouble:
1096 *i = (int) v.u.d;
1097 break;
1098 case FcTypeInteger:
1099 *i = v.u.i;
1100 break;
1101 default:
1102 return FcResultTypeMismatch;
1103 }
1104 return FcResultMatch;
1105}
1106
1107FcResult
bff80114 1108FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
24330d27
KP
1109{
1110 FcValue v;
1111 FcResult r;
1112
1113 r = FcPatternGet (p, object, id, &v);
1114 if (r != FcResultMatch)
1115 return r;
1116 switch (v.type) {
1117 case FcTypeDouble:
1118 *d = v.u.d;
1119 break;
1120 case FcTypeInteger:
1121 *d = (double) v.u.i;
1122 break;
1123 default:
1124 return FcResultTypeMismatch;
1125 }
1126 return FcResultMatch;
1127}
1128
1129FcResult
bff80114 1130FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
24330d27
KP
1131{
1132 FcValue v;
1133 FcResult r;
1134
1135 r = FcPatternGet (p, object, id, &v);
1136 if (r != FcResultMatch)
1137 return r;
1138 if (v.type != FcTypeString)
1139 return FcResultTypeMismatch;
e77c1718
PL
1140
1141 if (FcObjectToPtr(object) == FcObjectToPtr(FC_FILE))
1142 {
1143 const char *fn, *fpath;
1144 FcChar8 *fname;
1145 int size;
1146
1147 fn = FcPatternFindFullFname(p);
1148 if (fn)
1149 {
1150 *s = (FcChar8 *) fn;
1151 return FcResultMatch;
1152 }
1153
1154 if (!p->bank)
1155 {
1156 *s = (FcChar8 *) v.u.s;
1157 return FcResultMatch;
1158 }
1159
1160 fpath = FcCacheFindBankDir (p->bank);
1161 size = strlen((char*)fpath) + 1 + strlen ((char *)v.u.s) + 1;
1162 fname = malloc (size);
1163 if (!fname)
1164 return FcResultOutOfMemory;
1165
1166 FcMemAlloc (FC_MEM_STRING, size);
1167 strcpy ((char *)fname, (char *)fpath);
1168 strcat ((char *)fname, "/");
1169 strcat ((char *)fname, (char *)v.u.s);
1170
1171 FcPatternAddFullFname (p, (const char *)fname);
1172 *s = (FcChar8 *)fname;
1173 return FcResultMatch;
1174 }
1175
4262e0b3 1176 *s = (FcChar8 *) v.u.s;
24330d27
KP
1177 return FcResultMatch;
1178}
1179
1180FcResult
bff80114 1181FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
24330d27
KP
1182{
1183 FcValue v;
1184 FcResult r;
1185
1186 r = FcPatternGet (p, object, id, &v);
1187 if (r != FcResultMatch)
1188 return r;
1189 if (v.type != FcTypeMatrix)
1190 return FcResultTypeMismatch;
4262e0b3 1191 *m = (FcMatrix *)v.u.m;
24330d27
KP
1192 return FcResultMatch;
1193}
1194
1195
1196FcResult
bff80114 1197FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
24330d27
KP
1198{
1199 FcValue v;
1200 FcResult r;
1201
1202 r = FcPatternGet (p, object, id, &v);
1203 if (r != FcResultMatch)
1204 return r;
1205 if (v.type != FcTypeBool)
1206 return FcResultTypeMismatch;
1207 *b = v.u.b;
1208 return FcResultMatch;
1209}
1210
1211FcResult
bff80114 1212FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
24330d27
KP
1213{
1214 FcValue v;
1215 FcResult r;
1216
1217 r = FcPatternGet (p, object, id, &v);
1218 if (r != FcResultMatch)
1219 return r;
1220 if (v.type != FcTypeCharSet)
1221 return FcResultTypeMismatch;
4262e0b3 1222 *c = (FcCharSet *)v.u.c;
24330d27
KP
1223 return FcResultMatch;
1224}
1225
be094850 1226FcResult
bff80114 1227FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
be094850
KP
1228{
1229 FcValue v;
1230 FcResult r;
1231
1232 r = FcPatternGet (p, object, id, &v);
1233 if (r != FcResultMatch)
1234 return r;
1235 if (v.type != FcTypeFTFace)
1236 return FcResultTypeMismatch;
1237 *f = (FT_Face) v.u.f;
1238 return FcResultMatch;
1239}
1240
d8d73958 1241FcResult
bff80114 1242FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
d8d73958
KP
1243{
1244 FcValue v;
1245 FcResult r;
1246
1247 r = FcPatternGet (p, object, id, &v);
1248 if (r != FcResultMatch)
1249 return r;
1250 if (v.type != FcTypeLangSet)
1251 return FcResultTypeMismatch;
4262e0b3 1252 *ls = (FcLangSet *)v.u.l;
d8d73958
KP
1253 return FcResultMatch;
1254}
1255
24330d27 1256FcPattern *
bff80114 1257FcPatternDuplicate (const FcPattern *orig)
24330d27
KP
1258{
1259 FcPattern *new;
cd2ec1a9 1260 FcPatternElt *e;
24330d27 1261 int i;
cd2ec1a9 1262 FcValueListPtr l;
24330d27
KP
1263
1264 new = FcPatternCreate ();
1265 if (!new)
1266 goto bail0;
1267
cd2ec1a9
PL
1268 e = FcPatternEltU(orig->elts);
1269
24330d27
KP
1270 for (i = 0; i < orig->num; i++)
1271 {
cd2ec1a9
PL
1272 for (l = (e + i)->values;
1273 FcValueListPtrU(l);
1274 l = FcValueListPtrU(l)->next)
1275 if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object),
9fe2bd7a
PL
1276 FcValueCanonicalize(&FcValueListPtrU(l)->value),
1277 FcTrue))
24330d27
KP
1278 goto bail1;
1279 }
ea9726b6 1280 FcPatternTransferFullFname (new, orig);
24330d27
KP
1281
1282 return new;
1283
1284bail1:
1285 FcPatternDestroy (new);
1286bail0:
1287 return 0;
1288}
1289
6f6563ed
KP
1290void
1291FcPatternReference (FcPattern *p)
1292{
d8d73958
KP
1293 if (p->ref != FC_REF_CONSTANT)
1294 p->ref++;
6f6563ed
KP
1295}
1296
24330d27
KP
1297FcPattern *
1298FcPatternVaBuild (FcPattern *orig, va_list va)
1299{
1300 FcPattern *ret;
1301
1302 FcPatternVapBuild (ret, orig, va);
1303 return ret;
1304}
1305
1306FcPattern *
1307FcPatternBuild (FcPattern *orig, ...)
1308{
1309 va_list va;
1310
1311 va_start (va, orig);
1312 FcPatternVapBuild (orig, orig, va);
1313 va_end (va);
1314 return orig;
1315}
4f27c1c0
KP
1316
1317/*
1318 * Add all of the elements in 's' to 'p'
1319 */
1320FcBool
1321FcPatternAppend (FcPattern *p, FcPattern *s)
1322{
1323 int i;
1324 FcPatternElt *e;
cd2ec1a9 1325 FcValueListPtr v;
4f27c1c0
KP
1326
1327 for (i = 0; i < s->num; i++)
1328 {
cd2ec1a9
PL
1329 e = FcPatternEltU(s->elts)+i;
1330 for (v = e->values; FcValueListPtrU(v);
1331 v = FcValueListPtrU(v)->next)
4f27c1c0 1332 {
cd2ec1a9 1333 if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
4262e0b3 1334 FcValueCanonicalize(&FcValueListPtrU(v)->value),
cd2ec1a9 1335 FcValueListPtrU(v)->binding, FcTrue))
4f27c1c0
KP
1336 return FcFalse;
1337 }
1338 }
1339 return FcTrue;
1340}
1341
4262e0b3 1342#define OBJECT_HASH_SIZE 31
8245771d 1343static struct objectBucket {
4262e0b3
PL
1344 struct objectBucket *next;
1345 FcChar32 hash;
8245771d 1346} *FcObjectBuckets[OBJECT_HASH_SIZE];
4262e0b3 1347
8245771d
PL
1348const FcChar8 *
1349FcStrStaticName (const FcChar8 *name)
4262e0b3 1350{
8245771d
PL
1351 FcChar32 hash = FcStringHash (name);
1352 struct objectBucket **p;
1353 struct objectBucket *b;
1354 int size;
4262e0b3 1355
8245771d
PL
1356 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1357 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
1358 return (FcChar8 *) (b + 1);
1359 size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
23787a8f
PL
1360 b = malloc (size + sizeof (int));
1361 /* workaround glibc bug which reads strlen in groups of 4 */
1362 FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
4262e0b3
PL
1363 if (!b)
1364 return NULL;
1365 b->next = 0;
1366 b->hash = hash;
8245771d 1367 strcpy ((char *) (b + 1), (char *)name);
4262e0b3 1368 *p = b;
8245771d 1369 return (FcChar8 *) (b + 1);
4262e0b3
PL
1370}
1371
1372static void
7f37423d 1373FcStrStaticNameFini (void)
cd2ec1a9 1374{
4262e0b3
PL
1375 int i, size;
1376 struct objectBucket *b, *next;
1377 char *name;
1378
1379 for (i = 0; i < OBJECT_HASH_SIZE; i++)
cd2ec1a9 1380 {
4262e0b3
PL
1381 for (b = FcObjectBuckets[i]; b; b = next)
1382 {
1383 next = b->next;
1384 name = (char *) (b + 1);
1385 size = sizeof (struct objectBucket) + strlen (name) + 1;
1386 FcMemFree (FC_MEM_STATICSTR, size);
1387 free (b);
1388 }
1389 FcObjectBuckets[i] = 0;
cd2ec1a9
PL
1390 }
1391}
1392
4262e0b3
PL
1393void
1394FcPatternFini (void)
1395{
1396 FcPatternBaseThawAll ();
1397 FcValueListThawAll ();
7f37423d 1398 FcStrStaticNameFini ();
4262e0b3
PL
1399 FcObjectStaticNameFini ();
1400}
1401
1402FcPatternElt *
1403FcPatternEltU (FcPatternEltPtr pei)
1404{
1405 if (pei.bank == FC_BANK_DYNAMIC)
1406 return pei.u.dyn;
1407
1408 return &fcpatternelts[FcCacheBankToIndex(pei.bank)][pei.u.stat];
1409}
1410
cd2ec1a9
PL
1411static FcPatternEltPtr
1412FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1413{
1414 FcPatternEltPtr new;
4262e0b3 1415 new.bank = FC_BANK_DYNAMIC;
cd2ec1a9
PL
1416 new.u.dyn = e;
1417 return new;
1418}
1419
1420static FcPatternEltPtr
4262e0b3 1421FcPatternEltPtrCreateStatic (int bank, int i)
cd2ec1a9
PL
1422{
1423 FcPatternEltPtr new;
4262e0b3 1424 new.bank = bank;
cd2ec1a9
PL
1425 new.u.stat = i;
1426 return new;
1427}
1428
4262e0b3
PL
1429static void
1430FcStrNewBank (void);
1431static int
8245771d 1432FcStrNeededBytes (const FcChar8 * s);
7fd7221e
PL
1433static int
1434FcStrNeededBytesAlign (void);
4262e0b3
PL
1435static void *
1436FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
8245771d
PL
1437static const FcChar8 *
1438FcStrSerialize (int bank, const FcChar8 * s);
4262e0b3
PL
1439static void *
1440FcStrUnserialize (FcCache metadata, void *block_ptr);
1441
1442static void
1443FcValueListNewBank (void);
1444static int
1445FcValueListNeededBytes (FcValueList * vl);
7fd7221e
PL
1446static int
1447FcValueListNeededBytesAlign (void);
4262e0b3
PL
1448static void *
1449FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
1450static FcValueListPtr
1451FcValueListSerialize(int bank, FcValueList *pi);
1452static void *
1453FcValueListUnserialize (FcCache metadata, void *block_ptr);
cd2ec1a9 1454
cd2ec1a9
PL
1455
1456void
4262e0b3 1457FcPatternNewBank (void)
cd2ec1a9 1458{
cd2ec1a9 1459 fcpattern_count = 0;
cd2ec1a9 1460 fcpatternelt_count = 0;
cd2ec1a9 1461
4262e0b3
PL
1462 FcStrNewBank();
1463 FcValueListNewBank();
cd2ec1a9
PL
1464}
1465
4262e0b3
PL
1466int
1467FcPatternNeededBytes (FcPattern * p)
cd2ec1a9 1468{
4262e0b3 1469 int i, cum = 0, c;
cd2ec1a9
PL
1470
1471 fcpattern_count++;
1472 fcpatternelt_count += p->num;
1473
1474 for (i = 0; i < p->num; i++)
1475 {
4262e0b3
PL
1476 c = FcValueListNeededBytes (FcValueListPtrU
1477 (((FcPatternEltU(p->elts)+i)->values)));
1478 if (c < 0)
1479 return c;
1480 cum += c;
cd2ec1a9
PL
1481 }
1482
4262e0b3 1483 return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
cd2ec1a9
PL
1484}
1485
7fd7221e
PL
1486int
1487FcPatternNeededBytesAlign (void)
1488{
1489 return __alignof__ (FcPattern) + __alignof__ (FcPatternElt) +
1490 FcValueListNeededBytesAlign ();
1491}
1492
4262e0b3
PL
1493static FcBool
1494FcPatternEnsureBank (int bi)
cd2ec1a9 1495{
4262e0b3
PL
1496 FcPattern **pp;
1497 FcPatternElt **ep;
1498 int i;
cd2ec1a9 1499
4262e0b3 1500 if (!fcpatterns || fcpattern_bank_count <= bi)
cd2ec1a9 1501 {
4262e0b3
PL
1502 int new_count = bi + 4;
1503 pp = realloc (fcpatterns, sizeof (FcPattern *) * new_count);
1504 if (!pp)
1505 return 0;
cd2ec1a9 1506
4262e0b3
PL
1507 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern *) * new_count);
1508 fcpatterns = pp;
1509
1510 ep = realloc (fcpatternelts, sizeof (FcPatternElt *) * new_count);
1511 if (!ep)
1512 return 0;
1513
1514 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt *) * new_count);
1515 fcpatternelts = ep;
1516
1517 for (i = fcpattern_bank_count; i < new_count; i++)
cd2ec1a9 1518 {
4262e0b3
PL
1519 fcpatterns[i] = 0;
1520 fcpatternelts[i] = 0;
cd2ec1a9 1521 }
4262e0b3
PL
1522
1523 fcpattern_bank_count = new_count;
cd2ec1a9 1524 }
4262e0b3
PL
1525
1526 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
cd2ec1a9
PL
1527 return FcTrue;
1528}
1529
4262e0b3
PL
1530void *
1531FcPatternDistributeBytes (FcCache * metadata, void * block_ptr)
1532{
1533 int bi = FcCacheBankToIndex(metadata->bank);
1534
1535 if (!FcPatternEnsureBank(bi))
1536 return 0;
1537
1538 fcpattern_ptr = 0;
7fd7221e 1539 block_ptr = ALIGN(block_ptr, FcPattern);
4262e0b3
PL
1540 fcpatterns[bi] = (FcPattern *)block_ptr;
1541 block_ptr = (void *)((char *)block_ptr +
1542 (sizeof (FcPattern) * fcpattern_count));
1543
1544 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
1545 fcpatternelt_ptr = 0;
7fd7221e 1546 block_ptr = ALIGN(block_ptr, FcPatternElt);
4262e0b3
PL
1547 fcpatternelts[bi] = (FcPatternElt *)block_ptr;
1548 block_ptr = (void *)((char *)block_ptr +
1549 (sizeof (FcPatternElt) * fcpatternelt_count));
1550
1551 metadata->pattern_count = fcpattern_count;
1552 metadata->patternelt_count = fcpatternelt_count;
1553
1554 block_ptr = FcStrDistributeBytes (metadata, block_ptr);
1555 block_ptr = FcValueListDistributeBytes (metadata, block_ptr);
1556 return block_ptr;
1557}
1558
cd2ec1a9 1559FcPattern *
4262e0b3 1560FcPatternSerialize (int bank, FcPattern *old)
cd2ec1a9
PL
1561{
1562 FcPattern *p;
1563 FcPatternElt *e, *nep;
1564 FcValueList * nv;
1565 FcValueListPtr v, nv_head, nvp;
4262e0b3 1566 int i, elts, bi = FcCacheBankToIndex(bank);
cd2ec1a9 1567
4262e0b3
PL
1568 p = &fcpatterns[bi][fcpattern_ptr++];
1569 p->bank = bank;
cd2ec1a9 1570 elts = fcpatternelt_ptr;
4262e0b3 1571 nep = &fcpatternelts[bi][elts];
cd2ec1a9
PL
1572 if (!nep)
1573 return FcFalse;
212c9f43 1574
cd2ec1a9 1575 fcpatternelt_ptr += old->num;
212c9f43 1576
cd2ec1a9
PL
1577 for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++)
1578 {
1579 v = e->values;
4262e0b3 1580 nvp = nv_head = FcValueListSerialize(bank, FcValueListPtrU(v));
cd2ec1a9 1581 if (!FcValueListPtrU(nv_head))
4262e0b3 1582 return 0;
cd2ec1a9
PL
1583 nv = FcValueListPtrU(nvp);
1584
1585 for (;
1586 FcValueListPtrU(v);
1587 v = FcValueListPtrU(v)->next,
1588 nv = FcValueListPtrU(nv->next))
1589 {
1590
1591 if (FcValueListPtrU(FcValueListPtrU(v)->next))
1592 {
1593 nvp = FcValueListSerialize
4262e0b3 1594 (bank, FcValueListPtrU(FcValueListPtrU(v)->next));
cd2ec1a9
PL
1595 nv->next = nvp;
1596 }
1597 }
1598
1599 nep[i].values = nv_head;
7f37423d 1600 nep[i].object = e->object;
cd2ec1a9 1601 }
212c9f43
PL
1602
1603 p->elts = old->elts;
4262e0b3 1604 p->elts = FcPatternEltPtrCreateStatic(bank, elts);
cd2ec1a9 1605 p->size = old->num;
212c9f43 1606 p->num = old->num;
cd2ec1a9
PL
1607 p->ref = FC_REF_CONSTANT;
1608 return p;
212c9f43
PL
1609}
1610
7f37423d 1611void *
4262e0b3 1612FcPatternUnserialize (FcCache metadata, void *block_ptr)
212c9f43 1613{
4262e0b3
PL
1614 int bi = FcCacheBankToIndex(metadata.bank);
1615 if (!FcPatternEnsureBank(bi))
212c9f43 1616 return FcFalse;
212c9f43 1617
4262e0b3 1618 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata.pattern_count);
7fd7221e 1619 block_ptr = ALIGN(block_ptr, FcPattern);
4262e0b3
PL
1620 fcpatterns[bi] = (FcPattern *)block_ptr;
1621 block_ptr = (void *)((char *)block_ptr +
1622 (sizeof (FcPattern) * metadata.pattern_count));
1623
1624 FcMemAlloc (FC_MEM_PATELT,
1625 sizeof (FcPatternElt) * metadata.patternelt_count);
7fd7221e 1626 block_ptr = ALIGN(block_ptr, FcPatternElt);
4262e0b3
PL
1627 fcpatternelts[bi] = (FcPatternElt *)block_ptr;
1628 block_ptr = (void *)((char *)block_ptr +
1629 (sizeof (FcPatternElt) * metadata.patternelt_count));
1630
1631 block_ptr = FcStrUnserialize (metadata, block_ptr);
1632 block_ptr = FcValueListUnserialize (metadata, block_ptr);
1633
7f37423d 1634 return block_ptr;
212c9f43
PL
1635}
1636
4262e0b3
PL
1637static void
1638FcValueListNewBank (void)
212c9f43 1639{
4262e0b3
PL
1640 fcvaluelist_count = 0;
1641
1642 FcCharSetNewBank();
1643 FcLangSetNewBank();
1644}
212c9f43 1645
4262e0b3
PL
1646static int
1647FcValueListNeededBytes (FcValueList *p)
1648{
1649 FcValueList *vl;
1650 int cum = 0;
212c9f43 1651
4262e0b3
PL
1652 for (vl = p;
1653 vl;
1654 vl = FcValueListPtrU(vl->next))
212c9f43 1655 {
4262e0b3
PL
1656 FcValue v = FcValueCanonicalize(&vl->value); // unserialize just in case
1657
1658 switch (v.type)
1659 {
1660 case FcTypeCharSet:
1661 cum += FcCharSetNeededBytes(v.u.c);
1662 break;
1663 case FcTypeLangSet:
1664 cum += FcLangSetNeededBytes(v.u.l);
1665 break;
1666 case FcTypeString:
1667 cum += FcStrNeededBytes(v.u.s);
1668 default:
1669 break;
1670 }
1671 fcvaluelist_count++;
1672 cum += sizeof (FcValueList);
212c9f43 1673 }
4262e0b3
PL
1674
1675 return cum;
212c9f43
PL
1676}
1677
7fd7221e
PL
1678static int
1679FcValueListNeededBytesAlign (void)
1680{
1681 return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() +
1682 FcStrNeededBytesAlign() + __alignof__ (FcValueList);
1683}
1684
4262e0b3
PL
1685static FcBool
1686FcValueListEnsureBank (int bi)
212c9f43 1687{
4262e0b3
PL
1688 FcValueList **pvl;
1689
1690 if (!fcvaluelists || fcvaluelist_bank_count <= bi)
1691 {
1692 int new_count = bi + 2, i;
1693
1694 pvl = realloc (fcvaluelists, sizeof (FcValueList *) * new_count);
1695 if (!pvl)
1696 return FcFalse;
212c9f43 1697
4262e0b3
PL
1698 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList *) * new_count);
1699
1700 fcvaluelists = pvl;
1701 for (i = fcvaluelist_bank_count; i < new_count; i++)
1702 fcvaluelists[i] = 0;
1703
1704 fcvaluelist_bank_count = new_count;
1705 }
212c9f43
PL
1706 return FcTrue;
1707}
1708
4262e0b3
PL
1709static void *
1710FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
212c9f43 1711{
4262e0b3 1712 int bi = FcCacheBankToIndex(metadata->bank);
212c9f43 1713
4262e0b3
PL
1714 if (!FcValueListEnsureBank(bi))
1715 return 0;
212c9f43 1716
4262e0b3
PL
1717 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1718 fcvaluelist_ptr = 0;
7fd7221e 1719 block_ptr = ALIGN(block_ptr, FcValueList);
4262e0b3
PL
1720 fcvaluelists[bi] = (FcValueList *)block_ptr;
1721 block_ptr = (void *)((char *)block_ptr +
1722 (sizeof (FcValueList) * fcvaluelist_count));
1723 metadata->valuelist_count = fcvaluelist_count;
1724
1725 block_ptr = FcCharSetDistributeBytes(metadata, block_ptr);
1726 block_ptr = FcLangSetDistributeBytes(metadata, block_ptr);
1727
1728 return block_ptr;
212c9f43 1729}
cd2ec1a9 1730
4262e0b3
PL
1731static FcValueListPtr
1732FcValueListSerialize(int bank, FcValueList *pi)
cd2ec1a9
PL
1733{
1734 FcValueListPtr new;
1735 FcValue * v;
4262e0b3 1736 int bi = FcCacheBankToIndex(bank);
cd2ec1a9 1737
4262e0b3 1738 if (!pi)
cd2ec1a9 1739 {
4262e0b3
PL
1740 new.bank = FC_BANK_DYNAMIC;
1741 new.u.dyn = 0;
1742 return new;
cd2ec1a9
PL
1743 }
1744
4262e0b3
PL
1745 fcvaluelists[bi][fcvaluelist_ptr] = *pi;
1746 new.bank = bank;
cd2ec1a9 1747 new.u.stat = fcvaluelist_ptr++;
303bcf9b 1748 fcvaluelists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
4262e0b3 1749 v = &fcvaluelists[bi][new.u.stat].value;
cd2ec1a9
PL
1750 switch (v->type)
1751 {
1752 case FcTypeString:
4262e0b3 1753 if (v->u.s)
cd2ec1a9 1754 {
8245771d 1755 const FcChar8 * s = FcStrSerialize(bank, v->u.s);
4262e0b3 1756 if (!s)
cd2ec1a9 1757 return FcValueListPtrCreateDynamic(pi);
8245771d 1758 v->u.s_off = s - (const FcChar8 *)v;
4262e0b3 1759 v->type |= FC_STORAGE_STATIC;
cd2ec1a9
PL
1760 }
1761 break;
1762 case FcTypeMatrix:
cd2ec1a9
PL
1763 break;
1764 case FcTypeCharSet:
4262e0b3 1765 if (v->u.c)
cd2ec1a9 1766 {
4262e0b3
PL
1767 FcCharSet * c = FcCharSetSerialize(bank, (FcCharSet *)v->u.c);
1768 if (!c)
cd2ec1a9 1769 return FcValueListPtrCreateDynamic(pi);
4262e0b3
PL
1770 v->u.c_off = (char *)c - (char *)v;
1771 v->type |= FC_STORAGE_STATIC;
cd2ec1a9
PL
1772 }
1773 break;
1774 case FcTypeLangSet:
4262e0b3 1775 if (v->u.l)
cd2ec1a9 1776 {
4262e0b3
PL
1777 FcLangSet * l = FcLangSetSerialize(bank, (FcLangSet *)v->u.l);
1778 if (!l)
cd2ec1a9 1779 return FcValueListPtrCreateDynamic(pi);
4262e0b3
PL
1780 v->u.l_off = (char *)l - (char *)v;
1781 v->type |= FC_STORAGE_STATIC;
cd2ec1a9
PL
1782 }
1783 break;
1784 default:
1785 break;
1786 }
1787 return new;
1788}
1789
4262e0b3
PL
1790static void *
1791FcValueListUnserialize (FcCache metadata, void *block_ptr)
212c9f43 1792{
4262e0b3 1793 int bi = FcCacheBankToIndex(metadata.bank);
212c9f43 1794
4262e0b3
PL
1795 if (!FcValueListEnsureBank(bi))
1796 return 0;
212c9f43 1797
4262e0b3
PL
1798 FcMemAlloc (FC_MEM_VALLIST,
1799 sizeof (FcValueList) * metadata.valuelist_count);
7fd7221e 1800 block_ptr = ALIGN(block_ptr, FcValueList);
4262e0b3
PL
1801 fcvaluelists[bi] = (FcValueList *)block_ptr;
1802 block_ptr = (void *)((char *)block_ptr +
1803 (sizeof (FcValueList) * metadata.valuelist_count));
212c9f43 1804
4262e0b3
PL
1805 block_ptr = FcCharSetUnserialize(metadata, block_ptr);
1806 block_ptr = FcLangSetUnserialize(metadata, block_ptr);
1807
1808 return block_ptr;
212c9f43
PL
1809}
1810
cd2ec1a9
PL
1811FcValueList *
1812FcValueListPtrU (FcValueListPtr pi)
1813{
4262e0b3 1814 if (pi.bank == FC_BANK_DYNAMIC)
cd2ec1a9 1815 return pi.u.dyn;
4262e0b3
PL
1816
1817 return &fcvaluelists[FcCacheBankToIndex(pi.bank)][pi.u.stat];
cd2ec1a9
PL
1818}
1819
1820FcValueListPtr
1821FcValueListPtrCreateDynamic(FcValueList * p)
1822{
1823 FcValueListPtr r;
1824
4262e0b3 1825 r.bank = FC_BANK_DYNAMIC;
cd2ec1a9
PL
1826 r.u.dyn = p;
1827 return r;
4f27c1c0 1828}
0fa680f0 1829
8245771d 1830static FcChar8 ** static_strs;
4262e0b3 1831static int static_str_bank_count = 0, fcstr_ptr, fcstr_count;
0fa680f0 1832
4262e0b3 1833static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE];
0fa680f0 1834
4262e0b3
PL
1835static void
1836FcStrNewBank (void)
0fa680f0 1837{
4262e0b3
PL
1838 int i, size;
1839 struct objectBucket *b, *next;
1840 char *name;
0fa680f0 1841
4262e0b3 1842 for (i = 0; i < OBJECT_HASH_SIZE; i++)
0fa680f0 1843 {
4262e0b3 1844 for (b = FcStrBuckets[i]; b; b = next)
0fa680f0 1845 {
4262e0b3
PL
1846 next = b->next;
1847 name = (char *) (b + 1);
1848 size = sizeof (struct objectBucket) + strlen (name) + 1;
1849 FcMemFree (FC_MEM_STATICSTR, size);
1850 free (b);
0fa680f0 1851 }
4262e0b3 1852 FcStrBuckets[i] = 0;
0fa680f0
PL
1853 }
1854
4262e0b3
PL
1855 fcstr_count = 0;
1856}
0fa680f0 1857
4262e0b3 1858static int
8245771d 1859FcStrNeededBytes (const FcChar8 * s)
4262e0b3
PL
1860{
1861 FcChar32 hash = FcStringHash ((const FcChar8 *) s);
1862 struct objectBucket **p;
1863 struct objectBucket *b;
1864 int size;
0fa680f0 1865
4262e0b3 1866 for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
8245771d 1867 if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
4262e0b3 1868 return 0;
8245771d 1869 size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *);
0fa680f0 1870 b = malloc (size);
0fa680f0 1871 FcMemAlloc (FC_MEM_STATICSTR, size);
4262e0b3
PL
1872 if (!b)
1873 return -1;
0fa680f0
PL
1874 b->next = 0;
1875 b->hash = hash;
8245771d 1876 strcpy ((char *) (b + 1), (char *)s);
7fd7221e
PL
1877
1878 /* Yes, the following line is convoluted. However, it is
1879 * incorrect to replace the with a memset, because the C
1880 * specification doesn't guarantee that the null pointer is
1881 * the same as the zero bit pattern. */
8245771d 1882 *(char **)((char *) (b + 1) + strlen((char *)s) + 1) = 0;
0fa680f0 1883 *p = b;
0fa680f0 1884
8245771d
PL
1885 fcstr_count += strlen((char *)s) + 1;
1886 return strlen((char *)s) + 1;
0fa680f0
PL
1887}
1888
7fd7221e
PL
1889static int
1890FcStrNeededBytesAlign (void)
1891{
1892 return __alignof__ (char);
1893}
1894
0fa680f0 1895static FcBool
4262e0b3 1896FcStrEnsureBank (int bi)
0fa680f0 1897{
8245771d 1898 FcChar8 ** ss;
0fa680f0 1899
4262e0b3 1900 if (!static_strs || static_str_bank_count <= bi)
0fa680f0 1901 {
4262e0b3
PL
1902 int new_count = bi + 4, i;
1903 ss = realloc (static_strs, sizeof (const char *) * new_count);
1904 if (!ss)
1905 return FcFalse;
0fa680f0 1906
4262e0b3
PL
1907 FcMemAlloc (FC_MEM_STRING, sizeof (const char *) * (new_count-static_str_bank_count));
1908 static_strs = ss;
0fa680f0 1909
4262e0b3
PL
1910 for (i = static_str_bank_count; i < new_count; i++)
1911 static_strs[i] = 0;
1912 static_str_bank_count = new_count;
0fa680f0 1913 }
0fa680f0 1914 return FcTrue;
0fa680f0
PL
1915}
1916
4262e0b3
PL
1917static void *
1918FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
0fa680f0 1919{
4262e0b3
PL
1920 int bi = FcCacheBankToIndex(metadata->bank);
1921 if (!FcStrEnsureBank(bi))
1922 return 0;
0fa680f0 1923
4262e0b3 1924 FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
7fd7221e 1925 block_ptr = ALIGN (block_ptr, FcChar8);
8245771d 1926 static_strs[bi] = (FcChar8 *)block_ptr;
4262e0b3
PL
1927 block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
1928 metadata->str_count = fcstr_count;
1929 fcstr_ptr = 0;
0fa680f0 1930
4262e0b3 1931 return block_ptr;
0fa680f0 1932}
e1b9d091 1933
8245771d
PL
1934static const FcChar8 *
1935FcStrSerialize (int bank, const FcChar8 * s)
212c9f43 1936{
4262e0b3
PL
1937 FcChar32 hash = FcStringHash ((const FcChar8 *) s);
1938 struct objectBucket **p;
1939 struct objectBucket *b;
1940 int bi = FcCacheBankToIndex(bank);
212c9f43 1941
4262e0b3 1942 for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
8245771d 1943 if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
4262e0b3 1944 {
8245771d 1945 FcChar8 * t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
4262e0b3
PL
1946 if (!t)
1947 {
8245771d
PL
1948 strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
1949 *(FcChar8 **)((FcChar8 *) (b + 1) + strlen((char *)s) + 1) = (static_strs[bi] + fcstr_ptr);
1950 fcstr_ptr += strlen((char *)s) + 1;
1951 t = *(FcChar8 **)(((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1);
4262e0b3
PL
1952 }
1953 return t;
1954 }
1955 return 0;
212c9f43
PL
1956}
1957
4262e0b3
PL
1958static void *
1959FcStrUnserialize (FcCache metadata, void *block_ptr)
212c9f43 1960{
4262e0b3
PL
1961 int bi = FcCacheBankToIndex(metadata.bank);
1962 if (!FcStrEnsureBank(bi))
1963 return 0;
212c9f43 1964
4262e0b3 1965 FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata.str_count);
1c5b6345 1966 block_ptr = ALIGN (block_ptr, FcChar8);
8245771d 1967 static_strs[bi] = (FcChar8 *)block_ptr;
4262e0b3
PL
1968 block_ptr = (void *)((char *)block_ptr +
1969 (sizeof (char) * metadata.str_count));
e1b9d091 1970
4262e0b3 1971 return block_ptr;
e1b9d091
PL
1972}
1973
e77c1718
PL
1974/* we don't store these in the FcPattern itself because
1975 * we don't want to serialize the directory names */
1976
1977/* I suppose this should be cleaned, too... */
1978typedef struct _FcPatternDirMapping {
1979 const FcPattern *p;
1980 const char *fname;
1981} FcPatternDirMapping;
1982
1983#define PATTERNDIR_HASH_SIZE 31
1984static struct patternDirBucket {
1985 struct patternDirBucket *next;
1986 FcPatternDirMapping m;
1987} FcPatternDirBuckets[PATTERNDIR_HASH_SIZE];
1988
1989void
1990FcPatternAddFullFname (const FcPattern *p, const char *fname)
1991{
1992 struct patternDirBucket *pb;
1993
1994 /* N.B. FcPatternHash fails, since it's contents-based, not
1995 * address-based, and we're in the process of mutating the FcPattern. */
1996 for (pb = &FcPatternDirBuckets
1997 [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
1998 pb->m.p != p && pb->next;
1999 pb = pb->next)
2000 ;
2001
2002 if (pb->m.p == p)
2003 {
2004 pb->m.fname = fname;
2005 return;
2006 }
2007
2008 pb->next = malloc (sizeof (struct patternDirBucket));
2009 if (!pb->next)
2010 return;
2011 FcMemAlloc (FC_MEM_CACHE, sizeof (struct patternDirBucket));
2012
2013 pb->next->next = 0;
2014 pb->next->m.p = p;
2015 pb->next->m.fname = fname;
2016}
2017
793154ed 2018static const char *
e77c1718
PL
2019FcPatternFindFullFname (const FcPattern *p)
2020{
2021 struct patternDirBucket *pb;
2022
2023 for (pb = &FcPatternDirBuckets
2024 [((int)p / sizeof (FcPattern *)) % PATTERNDIR_HASH_SIZE];
2025 pb; pb = pb->next)
2026 if (pb->m.p == p)
2027 return pb->m.fname;
2028
2029 return 0;
2030}
2031
793154ed
PL
2032void
2033FcPatternTransferFullFname (const FcPattern *new, const FcPattern *orig)
2034{
2035 FcChar8 * s;
2036 FcPatternGetString (orig, FC_FILE, 0, &s);
7358dae4
PL
2037 FcPatternAddFullFname (new,
2038 (char *)FcStrCopy
2039 ((FcChar8 *)FcPatternFindFullFname(orig)));
793154ed 2040}