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