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