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