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