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