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