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