]> git.wh0rd.org - fontconfig.git/blame - src/fcpat.c
Revert to original FcFontSetMatch algorithm to avoid losing fonts.
[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
f045376c 25#include "fcint.h"
24330d27
KP
26#include <stdlib.h>
27#include <string.h>
d8d73958 28#include <assert.h>
24330d27 29
81fe99fd 30static FcPattern ** _fcPatterns = 0;
4262e0b3 31static int fcpattern_bank_count = 0, fcpattern_ptr, fcpattern_count;
81fe99fd 32FcPatternElt ** _fcPatternElts = 0;
cd2ec1a9 33static int fcpatternelt_ptr, fcpatternelt_count;
81fe99fd 34FcValueList ** _fcValueLists = 0;
4262e0b3 35static int fcvaluelist_bank_count = 0, fcvaluelist_ptr, fcvaluelist_count;
cd2ec1a9
PL
36
37static FcPatternEltPtr
38FcPatternEltPtrCreateDynamic (FcPatternElt * e);
9ede93f1
PL
39static FcBool
40FcStrHashed (const FcChar8 *name);
cd2ec1a9 41
24330d27
KP
42FcPattern *
43FcPatternCreate (void)
44{
45 FcPattern *p;
46
47 p = (FcPattern *) malloc (sizeof (FcPattern));
48 if (!p)
49 return 0;
50 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
51 p->num = 0;
52 p->size = 0;
cd2ec1a9 53 p->elts = FcPatternEltPtrCreateDynamic(0);
4262e0b3 54 p->bank = FC_BANK_DYNAMIC;
6f6563ed 55 p->ref = 1;
24330d27
KP
56 return p;
57}
58
59void
60FcValueDestroy (FcValue v)
61{
62 switch (v.type) {
63 case FcTypeString:
9ede93f1
PL
64 if (!FcStrHashed (v.u.s))
65 FcStrFree ((FcChar8 *) v.u.s);
24330d27
KP
66 break;
67 case FcTypeMatrix:
4262e0b3 68 FcMatrixFree ((FcMatrix *) v.u.m);
24330d27
KP
69 break;
70 case FcTypeCharSet:
4262e0b3 71 FcCharSetDestroy ((FcCharSet *) v.u.c);
24330d27 72 break;
d8d73958 73 case FcTypeLangSet:
4262e0b3 74 FcLangSetDestroy ((FcLangSet *) v.u.l);
d8d73958 75 break;
24330d27
KP
76 default:
77 break;
78 }
79}
80
4262e0b3
PL
81FcValue
82FcValueCanonicalize (const FcValue *v)
83{
84 if (v->type & FC_STORAGE_STATIC)
85 {
86 FcValue new = *v;
87
88 switch (v->type & ~FC_STORAGE_STATIC)
89 {
90 case FcTypeString:
91 new.u.s = fc_value_string(v);
92 new.type = FcTypeString;
93 break;
94 case FcTypeCharSet:
95 new.u.c = fc_value_charset(v);
96 new.type = FcTypeCharSet;
97 break;
98 case FcTypeLangSet:
99 new.u.l = fc_value_langset(v);
100 new.type = FcTypeLangSet;
101 break;
102 }
103 return new;
104 }
105 return *v;
106}
107
24330d27
KP
108FcValue
109FcValueSave (FcValue v)
110{
111 switch (v.type) {
112 case FcTypeString:
4262e0b3
PL
113 v.u.s = FcStrCopy (v.u.s);
114 if (!v.u.s)
24330d27
KP
115 v.type = FcTypeVoid;
116 break;
117 case FcTypeMatrix:
4262e0b3
PL
118 v.u.m = FcMatrixCopy (v.u.m);
119 if (!v.u.m)
24330d27
KP
120 v.type = FcTypeVoid;
121 break;
122 case FcTypeCharSet:
4262e0b3
PL
123 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
124 if (!v.u.c)
24330d27
KP
125 v.type = FcTypeVoid;
126 break;
d8d73958 127 case FcTypeLangSet:
4262e0b3
PL
128 v.u.l = FcLangSetCopy (v.u.l);
129 if (!v.u.l)
d8d73958
KP
130 v.type = FcTypeVoid;
131 break;
24330d27
KP
132 default:
133 break;
134 }
135 return v;
136}
137
138void
cd2ec1a9 139FcValueListDestroy (FcValueListPtr l)
24330d27 140{
cd2ec1a9
PL
141 FcValueListPtr next;
142 for (; FcValueListPtrU(l); l = next)
24330d27 143 {
cd2ec1a9 144 switch (FcValueListPtrU(l)->value.type) {
24330d27 145 case FcTypeString:
9ede93f1
PL
146 if (!FcStrHashed ((FcChar8 *)FcValueListPtrU(l)->value.u.s))
147 FcStrFree ((FcChar8 *)FcValueListPtrU(l)->value.u.s);
24330d27
KP
148 break;
149 case FcTypeMatrix:
4262e0b3 150 FcMatrixFree ((FcMatrix *)FcValueListPtrU(l)->value.u.m);
24330d27
KP
151 break;
152 case FcTypeCharSet:
cd2ec1a9 153 FcCharSetDestroy
4262e0b3 154 ((FcCharSet *) (FcValueListPtrU(l)->value.u.c));
24330d27 155 break;
d8d73958 156 case FcTypeLangSet:
cd2ec1a9 157 FcLangSetDestroy
4262e0b3 158 ((FcLangSet *) (FcValueListPtrU(l)->value.u.l));
d8d73958 159 break;
24330d27
KP
160 default:
161 break;
162 }
cd2ec1a9 163 next = FcValueListPtrU(l)->next;
24330d27 164 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
4262e0b3 165 if (l.bank == FC_BANK_DYNAMIC)
cd2ec1a9 166 free(l.u.dyn);
24330d27
KP
167 }
168}
169
0ab36ca8
KP
170FcBool
171FcValueEqual (FcValue va, FcValue vb)
172{
173 if (va.type != vb.type)
174 {
175 if (va.type == FcTypeInteger)
176 {
177 va.type = FcTypeDouble;
178 va.u.d = va.u.i;
179 }
180 if (vb.type == FcTypeInteger)
181 {
182 vb.type = FcTypeDouble;
183 vb.u.d = vb.u.i;
184 }
185 if (va.type != vb.type)
186 return FcFalse;
187 }
188 switch (va.type) {
189 case FcTypeVoid:
190 return FcTrue;
191 case FcTypeInteger:
192 return va.u.i == vb.u.i;
193 case FcTypeDouble:
194 return va.u.d == vb.u.d;
195 case FcTypeString:
4262e0b3 196 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
0ab36ca8
KP
197 case FcTypeBool:
198 return va.u.b == vb.u.b;
199 case FcTypeMatrix:
4262e0b3 200 return FcMatrixEqual (va.u.m, vb.u.m);
0ab36ca8 201 case FcTypeCharSet:
4262e0b3 202 return FcCharSetEqual (va.u.c, vb.u.c);
be094850
KP
203 case FcTypeFTFace:
204 return va.u.f == vb.u.f;
d8d73958 205 case FcTypeLangSet:
4262e0b3 206 return FcLangSetEqual (va.u.l, vb.u.l);
0ab36ca8
KP
207 }
208 return FcFalse;
209}
210
d0f07b8d
KP
211static FcChar32
212FcDoubleHash (double d)
213{
214 if (d < 0)
215 d = -d;
216 if (d > 0xffffffff)
217 d = 0xffffffff;
218 return (FcChar32) d;
219}
220
7f37423d 221FcChar32
d0f07b8d
KP
222FcStringHash (const FcChar8 *s)
223{
224 FcChar8 c;
225 FcChar32 h = 0;
226
227 if (s)
228 while ((c = *s++))
229 h = ((h << 1) | (h >> 31)) ^ c;
230 return h;
231}
232
233static FcChar32
efb11b36 234FcValueHash (const FcValue *v)
d0f07b8d 235{
efb11b36 236 switch (fc_storage_type(v)) {
d0f07b8d
KP
237 case FcTypeVoid:
238 return 0;
239 case FcTypeInteger:
efb11b36 240 return (FcChar32) v->u.i;
d0f07b8d 241 case FcTypeDouble:
efb11b36 242 return FcDoubleHash (v->u.d);
d0f07b8d 243 case FcTypeString:
efb11b36 244 return FcStringHash (fc_value_string(v));
d0f07b8d 245 case FcTypeBool:
efb11b36 246 return (FcChar32) v->u.b;
d0f07b8d 247 case FcTypeMatrix:
efb11b36
PL
248 return (FcDoubleHash (v->u.m->xx) ^
249 FcDoubleHash (v->u.m->xy) ^
250 FcDoubleHash (v->u.m->yx) ^
251 FcDoubleHash (v->u.m->yy));
d0f07b8d 252 case FcTypeCharSet:
efb11b36 253 return (FcChar32) fc_value_charset(v)->num;
d0f07b8d 254 case FcTypeFTFace:
efb11b36
PL
255 return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
256 FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
d8d73958 257 case FcTypeLangSet:
efb11b36 258 return FcLangSetHash (fc_value_langset(v));
d0f07b8d
KP
259 }
260 return FcFalse;
261}
262
0ab36ca8 263static FcBool
cd2ec1a9 264FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
0ab36ca8 265{
cd2ec1a9 266 if (FcValueListPtrU(la) == FcValueListPtrU(lb))
d8d73958
KP
267 return FcTrue;
268
cd2ec1a9 269 while (FcValueListPtrU(la) && FcValueListPtrU(lb))
0ab36ca8 270 {
cd2ec1a9
PL
271 if (!FcValueEqual (FcValueListPtrU(la)->value,
272 FcValueListPtrU(lb)->value))
0ab36ca8 273 return FcFalse;
cd2ec1a9
PL
274 la = FcValueListPtrU(la)->next;
275 lb = FcValueListPtrU(lb)->next;
0ab36ca8 276 }
cd2ec1a9 277 if (FcValueListPtrU(la) || FcValueListPtrU(lb))
0ab36ca8
KP
278 return FcFalse;
279 return FcTrue;
280}
281
d0f07b8d 282static FcChar32
cd2ec1a9 283FcValueListHash (FcValueListPtr l)
d0f07b8d
KP
284{
285 FcChar32 hash = 0;
efb11b36 286 FcValueList *l_ptrU;
d0f07b8d 287
efb11b36
PL
288 for (l_ptrU = FcValueListPtrU(l); l_ptrU;
289 l_ptrU = FcValueListPtrU(l_ptrU->next))
d0f07b8d 290 {
efb11b36 291 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l_ptrU->value);
d0f07b8d
KP
292 }
293 return hash;
294}
295
24330d27
KP
296void
297FcPatternDestroy (FcPattern *p)
298{
299 int i;
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
e9be9cd1
KP
319static int
320FcPatternPosition (const FcPattern *p, const char *object)
24330d27 321{
e9be9cd1 322 int low, high, mid, c;
cd2ec1a9 323 FcObjectPtr obj;
0ab36ca8 324
4262e0b3 325 obj = FcObjectToPtr(object);
0ab36ca8 326 low = 0;
e9be9cd1
KP
327 high = p->num - 1;
328 c = 1;
329 mid = 0;
330 while (low <= high)
24330d27 331 {
e9be9cd1 332 mid = (low + high) >> 1;
cd2ec1a9 333 c = FcObjectPtrCompare((FcPatternEltU(p->elts)+mid)->object, obj);
e9be9cd1
KP
334 if (c == 0)
335 return mid;
336 if (c < 0)
337 low = mid + 1;
0ab36ca8 338 else
e9be9cd1 339 high = mid - 1;
24330d27 340 }
e9be9cd1
KP
341 if (c < 0)
342 mid++;
343 return -(mid + 1);
344}
24330d27 345
e9be9cd1
KP
346FcPatternElt *
347FcPatternFindElt (const FcPattern *p, const char *object)
348{
349 int i = FcPatternPosition (p, object);
350 if (i < 0)
0ab36ca8 351 return 0;
cd2ec1a9 352 return FcPatternEltU(p->elts)+i;
e9be9cd1 353}
24330d27 354
e9be9cd1
KP
355FcPatternElt *
356FcPatternInsertElt (FcPattern *p, const char *object)
357{
358 int i;
359 FcPatternElt *e;
360
361 i = FcPatternPosition (p, object);
362 if (i < 0)
24330d27 363 {
e9be9cd1
KP
364 i = -i - 1;
365
cd2ec1a9 366 /* reallocate array */
e9be9cd1 367 if (p->num + 1 >= p->size)
24330d27 368 {
e9be9cd1 369 int s = p->size + 16;
cd2ec1a9
PL
370 if (FcPatternEltU(p->elts))
371 {
372 FcPatternElt *e0 = FcPatternEltU(p->elts);
373 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
374 if (!e) /* maybe it was mmapped */
375 {
376 e = malloc(s * sizeof (FcPatternElt));
377 if (e)
378 memcpy(e, e0, p->num * sizeof (FcPatternElt));
379 }
380 }
e9be9cd1
KP
381 else
382 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
383 if (!e)
384 return FcFalse;
cd2ec1a9 385 p->elts = FcPatternEltPtrCreateDynamic(e);
e9be9cd1
KP
386 if (p->size)
387 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
388 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
389 while (p->size < s)
390 {
0fa680f0 391 (FcPatternEltU(p->elts)+p->size)->object = 0;
cd2ec1a9
PL
392 (FcPatternEltU(p->elts)+p->size)->values =
393 FcValueListPtrCreateDynamic(0);
e9be9cd1
KP
394 p->size++;
395 }
24330d27 396 }
e9be9cd1
KP
397
398 /* move elts up */
cd2ec1a9
PL
399 memmove (FcPatternEltU(p->elts) + i + 1,
400 FcPatternEltU(p->elts) + i,
e9be9cd1
KP
401 sizeof (FcPatternElt) *
402 (p->num - i));
403
404 /* bump count */
405 p->num++;
406
4262e0b3 407 (FcPatternEltU(p->elts)+i)->object = FcObjectToPtr (object);
cd2ec1a9 408 (FcPatternEltU(p->elts)+i)->values = FcValueListPtrCreateDynamic(0);
24330d27
KP
409 }
410
cd2ec1a9 411 return FcPatternEltU(p->elts)+i;
24330d27
KP
412}
413
0ab36ca8 414FcBool
e9be9cd1 415FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
0ab36ca8
KP
416{
417 int i;
418
bd724c85
KP
419 if (pa == pb)
420 return FcTrue;
421
0ab36ca8
KP
422 if (pa->num != pb->num)
423 return FcFalse;
424 for (i = 0; i < pa->num; i++)
425 {
cd2ec1a9
PL
426 if (FcObjectPtrCompare((FcPatternEltU(pa->elts)+i)->object,
427 (FcPatternEltU(pb->elts)+i)->object) != 0)
0ab36ca8 428 return FcFalse;
cd2ec1a9
PL
429 if (!FcValueListEqual ((FcPatternEltU(pa->elts)+i)->values,
430 (FcPatternEltU(pb->elts)+i)->values))
0ab36ca8
KP
431 return FcFalse;
432 }
433 return FcTrue;
434}
435
d0f07b8d
KP
436FcChar32
437FcPatternHash (const FcPattern *p)
438{
439 int i;
440 FcChar32 h = 0;
441
442 for (i = 0; i < p->num; i++)
443 {
444 h = (((h << 1) | (h >> 31)) ^
8245771d 445 FcStringHash ((FcChar8 *)FcObjectPtrU ((FcPatternEltU(p->elts)+i)->object)) ^
cd2ec1a9 446 FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
d0f07b8d
KP
447 }
448 return h;
449}
450
e9be9cd1 451FcBool
cd2ec1a9 452FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
e9be9cd1
KP
453{
454 FcPatternElt *ea, *eb;
455 int i;
456
457 for (i = 0; i < os->nobject; i++)
458 {
4262e0b3
PL
459 ea = FcPatternFindElt (pai, os->objects[i]);
460 eb = FcPatternFindElt (pbi, os->objects[i]);
e9be9cd1
KP
461 if (ea)
462 {
463 if (!eb)
464 return FcFalse;
465 if (!FcValueListEqual (ea->values, eb->values))
466 return FcFalse;
467 }
468 else
469 {
470 if (eb)
471 return FcFalse;
472 }
473 }
474 return FcTrue;
475}
476
24330d27 477FcBool
82f4243f
KP
478FcPatternAddWithBinding (FcPattern *p,
479 const char *object,
480 FcValue value,
481 FcValueBinding binding,
482 FcBool append)
24330d27
KP
483{
484 FcPatternElt *e;
cd2ec1a9 485 FcValueListPtr new, *prev;
1c9fdcca
PL
486 FcValueList *newp;
487 FcObjectPtr objectPtr;
24330d27 488
d8d73958
KP
489 if (p->ref == FC_REF_CONSTANT)
490 goto bail0;
491
cd2ec1a9
PL
492 newp = malloc (sizeof (FcValueList));
493 if (!newp)
24330d27
KP
494 goto bail0;
495
cd2ec1a9
PL
496 memset(newp, 0, sizeof (FcValueList));
497 new = FcValueListPtrCreateDynamic(newp);
24330d27
KP
498 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
499 /* dup string */
575a37b7
PL
500 if (value.type == FcTypeString)
501 {
502 value.u.s = FcStrStaticName (value.u.s);
503 if (!value.u.s)
504 value.type = FcTypeVoid;
505 }
506 else
507 value = FcValueSave (value);
24330d27
KP
508 if (value.type == FcTypeVoid)
509 goto bail1;
510
1c9fdcca
PL
511 /* quick and dirty hack to enable FcCompareFamily/FcCompareString
512 * speedup: only allow strings to be added under the FC_FAMILY,
513 * FC_FOUNDRY, FC_STYLE, FC_RASTERIZER keys.
514 * and charsets under FC_CHARSET key.
515 * This is slightly semantically different from the old behaviour,
516 * but fonts shouldn't be getting non-strings here anyway.
4f8b266f 517 * a better hack would use FcBaseObjectTypes to check all objects. */
1c9fdcca
PL
518 objectPtr = FcObjectToPtr(object);
519 if ((objectPtr == FcObjectToPtr(FC_FAMILY)
520 || objectPtr == FcObjectToPtr(FC_FOUNDRY)
521 || objectPtr == FcObjectToPtr(FC_STYLE)
522 || objectPtr == FcObjectToPtr(FC_RASTERIZER))
523 && value.type != FcTypeString)
524 goto bail1;
525 if (objectPtr == FcObjectToPtr(FC_CHARSET)
526 && value.type != FcTypeCharSet)
4f8b266f
PL
527 goto bail1;
528
cd2ec1a9
PL
529 FcValueListPtrU(new)->value = value;
530 FcValueListPtrU(new)->binding = binding;
531 FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
24330d27 532
e9be9cd1 533 e = FcPatternInsertElt (p, object);
24330d27
KP
534 if (!e)
535 goto bail2;
536
537 if (append)
538 {
cd2ec1a9
PL
539 for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
540 ;
24330d27
KP
541 *prev = new;
542 }
543 else
544 {
cd2ec1a9 545 FcValueListPtrU(new)->next = e->values;
24330d27
KP
546 e->values = new;
547 }
548
549 return FcTrue;
550
551bail2:
552 switch (value.type) {
553 case FcTypeString:
4262e0b3 554 FcStrFree ((FcChar8 *) value.u.s);
24330d27
KP
555 break;
556 case FcTypeMatrix:
4262e0b3 557 FcMatrixFree ((FcMatrix *) value.u.m);
24330d27
KP
558 break;
559 case FcTypeCharSet:
4262e0b3 560 FcCharSetDestroy ((FcCharSet *) value.u.c);
24330d27 561 break;
d8d73958 562 case FcTypeLangSet:
4262e0b3 563 FcLangSetDestroy ((FcLangSet *) value.u.l);
d8d73958 564 break;
24330d27
KP
565 default:
566 break;
567 }
568bail1:
569 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
cd2ec1a9 570 free (FcValueListPtrU(new));
24330d27
KP
571bail0:
572 return FcFalse;
573}
574
82f4243f
KP
575FcBool
576FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
577{
578 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
579}
580
581FcBool
582FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
583{
584 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
585}
586
24330d27
KP
587FcBool
588FcPatternDel (FcPattern *p, const char *object)
589{
590 FcPatternElt *e;
24330d27 591
e9be9cd1 592 e = FcPatternFindElt (p, object);
24330d27
KP
593 if (!e)
594 return FcFalse;
595
24330d27
KP
596 /* destroy value */
597 FcValueListDestroy (e->values);
598
599 /* shuffle existing ones down */
cd2ec1a9
PL
600 memmove (e, e+1,
601 (FcPatternEltU(p->elts) + p->num - (e + 1)) *
602 sizeof (FcPatternElt));
24330d27 603 p->num--;
0fa680f0 604 (FcPatternEltU(p->elts)+p->num)->object = 0;
cd2ec1a9 605 (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
24330d27
KP
606 return FcTrue;
607}
608
4f27c1c0
KP
609FcBool
610FcPatternRemove (FcPattern *p, const char *object, int id)
611{
cd2ec1a9
PL
612 FcPatternElt *e;
613 FcValueListPtr *prev, l;
4f27c1c0
KP
614
615 e = FcPatternFindElt (p, object);
616 if (!e)
617 return FcFalse;
cd2ec1a9
PL
618 for (prev = &e->values;
619 FcValueListPtrU(l = *prev);
620 prev = &FcValueListPtrU(l)->next)
4f27c1c0
KP
621 {
622 if (!id)
623 {
cd2ec1a9
PL
624 *prev = FcValueListPtrU(l)->next;
625 FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
4f27c1c0 626 FcValueListDestroy (l);
cd2ec1a9 627 if (!FcValueListPtrU(e->values))
4f27c1c0
KP
628 FcPatternDel (p, object);
629 return FcTrue;
630 }
631 id--;
632 }
633 return FcFalse;
634}
635
24330d27
KP
636FcBool
637FcPatternAddInteger (FcPattern *p, const char *object, int i)
638{
639 FcValue v;
640
641 v.type = FcTypeInteger;
642 v.u.i = i;
643 return FcPatternAdd (p, object, v, FcTrue);
644}
645
646FcBool
647FcPatternAddDouble (FcPattern *p, const char *object, double d)
648{
649 FcValue v;
650
651 v.type = FcTypeDouble;
652 v.u.d = d;
653 return FcPatternAdd (p, object, v, FcTrue);
654}
655
656
657FcBool
ccb3e93b 658FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
24330d27
KP
659{
660 FcValue v;
661
204da5a8
PL
662 if (!s)
663 {
664 v.type = FcTypeVoid;
665 v.u.s = 0;
666 return FcPatternAdd (p, object, v, FcTrue);
667 }
668
24330d27 669 v.type = FcTypeString;
7f37423d 670 v.u.s = FcStrStaticName(s);
24330d27
KP
671 return FcPatternAdd (p, object, v, FcTrue);
672}
673
674FcBool
675FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
676{
677 FcValue v;
678
679 v.type = FcTypeMatrix;
4262e0b3 680 v.u.m = s;
24330d27
KP
681 return FcPatternAdd (p, object, v, FcTrue);
682}
683
684
685FcBool
686FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
687{
688 FcValue v;
689
690 v.type = FcTypeBool;
691 v.u.b = b;
692 return FcPatternAdd (p, object, v, FcTrue);
693}
694
695FcBool
696FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
697{
698 FcValue v;
699
700 v.type = FcTypeCharSet;
4262e0b3 701 v.u.c = (FcCharSet *)c;
24330d27
KP
702 return FcPatternAdd (p, object, v, FcTrue);
703}
704
be094850
KP
705FcBool
706FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
707{
708 FcValue v;
709
710 v.type = FcTypeFTFace;
711 v.u.f = (void *) f;
712 return FcPatternAdd (p, object, v, FcTrue);
713}
714
d8d73958
KP
715FcBool
716FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
717{
718 FcValue v;
719
720 v.type = FcTypeLangSet;
4262e0b3 721 v.u.l = (FcLangSet *)ls;
d8d73958
KP
722 return FcPatternAdd (p, object, v, FcTrue);
723}
724
24330d27 725FcResult
bff80114 726FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
24330d27
KP
727{
728 FcPatternElt *e;
cd2ec1a9 729 FcValueListPtr l;
24330d27 730
e9be9cd1 731 e = FcPatternFindElt (p, object);
24330d27
KP
732 if (!e)
733 return FcResultNoMatch;
cd2ec1a9 734 for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
24330d27
KP
735 {
736 if (!id)
737 {
4262e0b3 738 *v = FcValueCanonicalize(&FcValueListPtrU(l)->value);
24330d27
KP
739 return FcResultMatch;
740 }
741 id--;
742 }
743 return FcResultNoId;
744}
745
746FcResult
bff80114 747FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
24330d27
KP
748{
749 FcValue v;
750 FcResult r;
751
752 r = FcPatternGet (p, object, id, &v);
753 if (r != FcResultMatch)
754 return r;
755 switch (v.type) {
756 case FcTypeDouble:
757 *i = (int) v.u.d;
758 break;
759 case FcTypeInteger:
760 *i = v.u.i;
761 break;
762 default:
763 return FcResultTypeMismatch;
764 }
765 return FcResultMatch;
766}
767
768FcResult
bff80114 769FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
24330d27
KP
770{
771 FcValue v;
772 FcResult r;
773
774 r = FcPatternGet (p, object, id, &v);
775 if (r != FcResultMatch)
776 return r;
777 switch (v.type) {
778 case FcTypeDouble:
779 *d = v.u.d;
780 break;
781 case FcTypeInteger:
782 *d = (double) v.u.i;
783 break;
784 default:
785 return FcResultTypeMismatch;
786 }
787 return FcResultMatch;
788}
789
790FcResult
bff80114 791FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
24330d27
KP
792{
793 FcValue v;
794 FcResult r;
795
796 r = FcPatternGet (p, object, id, &v);
797 if (r != FcResultMatch)
798 return r;
799 if (v.type != FcTypeString)
800 return FcResultTypeMismatch;
e77c1718 801
4262e0b3 802 *s = (FcChar8 *) v.u.s;
24330d27
KP
803 return FcResultMatch;
804}
805
806FcResult
bff80114 807FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
24330d27
KP
808{
809 FcValue v;
810 FcResult r;
811
812 r = FcPatternGet (p, object, id, &v);
813 if (r != FcResultMatch)
814 return r;
815 if (v.type != FcTypeMatrix)
816 return FcResultTypeMismatch;
4262e0b3 817 *m = (FcMatrix *)v.u.m;
24330d27
KP
818 return FcResultMatch;
819}
820
821
822FcResult
bff80114 823FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
24330d27
KP
824{
825 FcValue v;
826 FcResult r;
827
828 r = FcPatternGet (p, object, id, &v);
829 if (r != FcResultMatch)
830 return r;
831 if (v.type != FcTypeBool)
832 return FcResultTypeMismatch;
833 *b = v.u.b;
834 return FcResultMatch;
835}
836
837FcResult
bff80114 838FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
24330d27
KP
839{
840 FcValue v;
841 FcResult r;
842
843 r = FcPatternGet (p, object, id, &v);
844 if (r != FcResultMatch)
845 return r;
846 if (v.type != FcTypeCharSet)
847 return FcResultTypeMismatch;
4262e0b3 848 *c = (FcCharSet *)v.u.c;
24330d27
KP
849 return FcResultMatch;
850}
851
be094850 852FcResult
bff80114 853FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
be094850
KP
854{
855 FcValue v;
856 FcResult r;
857
858 r = FcPatternGet (p, object, id, &v);
859 if (r != FcResultMatch)
860 return r;
861 if (v.type != FcTypeFTFace)
862 return FcResultTypeMismatch;
863 *f = (FT_Face) v.u.f;
864 return FcResultMatch;
865}
866
d8d73958 867FcResult
bff80114 868FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
d8d73958
KP
869{
870 FcValue v;
871 FcResult r;
872
873 r = FcPatternGet (p, object, id, &v);
874 if (r != FcResultMatch)
875 return r;
876 if (v.type != FcTypeLangSet)
877 return FcResultTypeMismatch;
4262e0b3 878 *ls = (FcLangSet *)v.u.l;
d8d73958
KP
879 return FcResultMatch;
880}
881
24330d27 882FcPattern *
bff80114 883FcPatternDuplicate (const FcPattern *orig)
24330d27
KP
884{
885 FcPattern *new;
cd2ec1a9 886 FcPatternElt *e;
24330d27 887 int i;
cd2ec1a9 888 FcValueListPtr l;
24330d27
KP
889
890 new = FcPatternCreate ();
891 if (!new)
892 goto bail0;
893
cd2ec1a9
PL
894 e = FcPatternEltU(orig->elts);
895
24330d27
KP
896 for (i = 0; i < orig->num; i++)
897 {
cd2ec1a9
PL
898 for (l = (e + i)->values;
899 FcValueListPtrU(l);
900 l = FcValueListPtrU(l)->next)
901 if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object),
9fe2bd7a
PL
902 FcValueCanonicalize(&FcValueListPtrU(l)->value),
903 FcTrue))
24330d27
KP
904 goto bail1;
905 }
906
907 return new;
908
909bail1:
910 FcPatternDestroy (new);
911bail0:
912 return 0;
913}
914
6f6563ed
KP
915void
916FcPatternReference (FcPattern *p)
917{
d8d73958
KP
918 if (p->ref != FC_REF_CONSTANT)
919 p->ref++;
6f6563ed
KP
920}
921
24330d27
KP
922FcPattern *
923FcPatternVaBuild (FcPattern *orig, va_list va)
924{
925 FcPattern *ret;
926
927 FcPatternVapBuild (ret, orig, va);
928 return ret;
929}
930
931FcPattern *
932FcPatternBuild (FcPattern *orig, ...)
933{
934 va_list va;
935
936 va_start (va, orig);
937 FcPatternVapBuild (orig, orig, va);
938 va_end (va);
939 return orig;
940}
4f27c1c0
KP
941
942/*
943 * Add all of the elements in 's' to 'p'
944 */
945FcBool
946FcPatternAppend (FcPattern *p, FcPattern *s)
947{
948 int i;
949 FcPatternElt *e;
cd2ec1a9 950 FcValueListPtr v;
4f27c1c0
KP
951
952 for (i = 0; i < s->num; i++)
953 {
cd2ec1a9
PL
954 e = FcPatternEltU(s->elts)+i;
955 for (v = e->values; FcValueListPtrU(v);
956 v = FcValueListPtrU(v)->next)
4f27c1c0 957 {
cd2ec1a9 958 if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
4262e0b3 959 FcValueCanonicalize(&FcValueListPtrU(v)->value),
cd2ec1a9 960 FcValueListPtrU(v)->binding, FcTrue))
4f27c1c0
KP
961 return FcFalse;
962 }
963 }
964 return FcTrue;
965}
966
4262e0b3 967#define OBJECT_HASH_SIZE 31
8245771d 968static struct objectBucket {
4262e0b3
PL
969 struct objectBucket *next;
970 FcChar32 hash;
8245771d 971} *FcObjectBuckets[OBJECT_HASH_SIZE];
4262e0b3 972
9ede93f1
PL
973static FcBool
974FcStrHashed (const FcChar8 *name)
975{
976 FcChar32 hash = FcStringHash (name);
977 struct objectBucket **p;
978 struct objectBucket *b;
979
980 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
981 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
982 return FcTrue;
983 return FcFalse;
984}
985
8245771d
PL
986const FcChar8 *
987FcStrStaticName (const FcChar8 *name)
4262e0b3 988{
8245771d
PL
989 FcChar32 hash = FcStringHash (name);
990 struct objectBucket **p;
991 struct objectBucket *b;
992 int size;
4262e0b3 993
8245771d
PL
994 for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
995 if (b->hash == hash && !strcmp ((char *)name, (char *) (b + 1)))
996 return (FcChar8 *) (b + 1);
997 size = sizeof (struct objectBucket) + strlen ((char *)name) + 1;
23787a8f
PL
998 b = malloc (size + sizeof (int));
999 /* workaround glibc bug which reads strlen in groups of 4 */
1000 FcMemAlloc (FC_MEM_STATICSTR, size + sizeof (int));
4262e0b3
PL
1001 if (!b)
1002 return NULL;
1003 b->next = 0;
1004 b->hash = hash;
8245771d 1005 strcpy ((char *) (b + 1), (char *)name);
4262e0b3 1006 *p = b;
8245771d 1007 return (FcChar8 *) (b + 1);
4262e0b3
PL
1008}
1009
1010static void
7f37423d 1011FcStrStaticNameFini (void)
cd2ec1a9 1012{
4262e0b3
PL
1013 int i, size;
1014 struct objectBucket *b, *next;
1015 char *name;
1016
1017 for (i = 0; i < OBJECT_HASH_SIZE; i++)
cd2ec1a9 1018 {
4262e0b3
PL
1019 for (b = FcObjectBuckets[i]; b; b = next)
1020 {
1021 next = b->next;
1022 name = (char *) (b + 1);
1023 size = sizeof (struct objectBucket) + strlen (name) + 1;
1024 FcMemFree (FC_MEM_STATICSTR, size);
1025 free (b);
1026 }
1027 FcObjectBuckets[i] = 0;
cd2ec1a9
PL
1028 }
1029}
1030
4262e0b3
PL
1031void
1032FcPatternFini (void)
1033{
7f37423d 1034 FcStrStaticNameFini ();
4262e0b3
PL
1035 FcObjectStaticNameFini ();
1036}
1037
cd2ec1a9
PL
1038static FcPatternEltPtr
1039FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1040{
1041 FcPatternEltPtr new;
4262e0b3 1042 new.bank = FC_BANK_DYNAMIC;
cd2ec1a9
PL
1043 new.u.dyn = e;
1044 return new;
1045}
1046
1047static FcPatternEltPtr
4262e0b3 1048FcPatternEltPtrCreateStatic (int bank, int i)
cd2ec1a9
PL
1049{
1050 FcPatternEltPtr new;
4262e0b3 1051 new.bank = bank;
cd2ec1a9
PL
1052 new.u.stat = i;
1053 return new;
1054}
1055
4262e0b3
PL
1056static void
1057FcStrNewBank (void);
1058static int
8245771d 1059FcStrNeededBytes (const FcChar8 * s);
7fd7221e
PL
1060static int
1061FcStrNeededBytesAlign (void);
4262e0b3
PL
1062static void *
1063FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
8245771d
PL
1064static const FcChar8 *
1065FcStrSerialize (int bank, const FcChar8 * s);
4262e0b3 1066static void *
61571f3f 1067FcStrUnserialize (FcCache * metadata, void *block_ptr);
4262e0b3
PL
1068
1069static void
1070FcValueListNewBank (void);
1071static int
1072FcValueListNeededBytes (FcValueList * vl);
7fd7221e
PL
1073static int
1074FcValueListNeededBytesAlign (void);
4262e0b3
PL
1075static void *
1076FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
1077static FcValueListPtr
1078FcValueListSerialize(int bank, FcValueList *pi);
1079static void *
61571f3f 1080FcValueListUnserialize (FcCache * metadata, void *block_ptr);
cd2ec1a9 1081
cd2ec1a9
PL
1082
1083void
4262e0b3 1084FcPatternNewBank (void)
cd2ec1a9 1085{
cd2ec1a9 1086 fcpattern_count = 0;
cd2ec1a9 1087 fcpatternelt_count = 0;
cd2ec1a9 1088
4262e0b3
PL
1089 FcStrNewBank();
1090 FcValueListNewBank();
cd2ec1a9
PL
1091}
1092
4262e0b3
PL
1093int
1094FcPatternNeededBytes (FcPattern * p)
cd2ec1a9 1095{
4262e0b3 1096 int i, cum = 0, c;
cd2ec1a9
PL
1097
1098 fcpattern_count++;
1099 fcpatternelt_count += p->num;
1100
1101 for (i = 0; i < p->num; i++)
1102 {
4262e0b3
PL
1103 c = FcValueListNeededBytes (FcValueListPtrU
1104 (((FcPatternEltU(p->elts)+i)->values)));
1105 if (c < 0)
1106 return c;
1107 cum += c;
cd2ec1a9
PL
1108 }
1109
4262e0b3 1110 return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
cd2ec1a9
PL
1111}
1112
7fd7221e
PL
1113int
1114FcPatternNeededBytesAlign (void)
1115{
44415a07 1116 return fc_alignof (FcPattern) + fc_alignof (FcPatternElt) +
7fd7221e
PL
1117 FcValueListNeededBytesAlign ();
1118}
1119
4262e0b3
PL
1120static FcBool
1121FcPatternEnsureBank (int bi)
cd2ec1a9 1122{
4262e0b3
PL
1123 FcPattern **pp;
1124 FcPatternElt **ep;
1125 int i;
cd2ec1a9 1126
81fe99fd 1127 if (!_fcPatterns || fcpattern_bank_count <= bi)
cd2ec1a9 1128 {
4262e0b3 1129 int new_count = bi + 4;
81fe99fd 1130 pp = realloc (_fcPatterns, sizeof (FcPattern *) * new_count);
4262e0b3
PL
1131 if (!pp)
1132 return 0;
cd2ec1a9 1133
4262e0b3 1134 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern *) * new_count);
81fe99fd 1135 _fcPatterns = pp;
4262e0b3 1136
81fe99fd 1137 ep = realloc (_fcPatternElts, sizeof (FcPatternElt *) * new_count);
4262e0b3
PL
1138 if (!ep)
1139 return 0;
1140
1141 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt *) * new_count);
81fe99fd 1142 _fcPatternElts = ep;
4262e0b3
PL
1143
1144 for (i = fcpattern_bank_count; i < new_count; i++)
cd2ec1a9 1145 {
81fe99fd
PL
1146 _fcPatterns[i] = 0;
1147 _fcPatternElts[i] = 0;
cd2ec1a9 1148 }
4262e0b3
PL
1149
1150 fcpattern_bank_count = new_count;
cd2ec1a9 1151 }
4262e0b3
PL
1152
1153 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
cd2ec1a9
PL
1154 return FcTrue;
1155}
1156
4262e0b3
PL
1157void *
1158FcPatternDistributeBytes (FcCache * metadata, void * block_ptr)
1159{
1160 int bi = FcCacheBankToIndex(metadata->bank);
1161
1162 if (!FcPatternEnsureBank(bi))
1163 return 0;
1164
1165 fcpattern_ptr = 0;
7fd7221e 1166 block_ptr = ALIGN(block_ptr, FcPattern);
81fe99fd 1167 _fcPatterns[bi] = (FcPattern *)block_ptr;
4262e0b3
PL
1168 block_ptr = (void *)((char *)block_ptr +
1169 (sizeof (FcPattern) * fcpattern_count));
1170
1171 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
1172 fcpatternelt_ptr = 0;
7fd7221e 1173 block_ptr = ALIGN(block_ptr, FcPatternElt);
81fe99fd 1174 _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
4262e0b3
PL
1175 block_ptr = (void *)((char *)block_ptr +
1176 (sizeof (FcPatternElt) * fcpatternelt_count));
1177
1178 metadata->pattern_count = fcpattern_count;
1179 metadata->patternelt_count = fcpatternelt_count;
1180
1181 block_ptr = FcStrDistributeBytes (metadata, block_ptr);
1182 block_ptr = FcValueListDistributeBytes (metadata, block_ptr);
1183 return block_ptr;
1184}
1185
cd2ec1a9 1186FcPattern *
4262e0b3 1187FcPatternSerialize (int bank, FcPattern *old)
cd2ec1a9
PL
1188{
1189 FcPattern *p;
1190 FcPatternElt *e, *nep;
1191 FcValueList * nv;
1192 FcValueListPtr v, nv_head, nvp;
4262e0b3 1193 int i, elts, bi = FcCacheBankToIndex(bank);
cd2ec1a9 1194
81fe99fd 1195 p = &_fcPatterns[bi][fcpattern_ptr++];
4262e0b3 1196 p->bank = bank;
cd2ec1a9 1197 elts = fcpatternelt_ptr;
81fe99fd 1198 nep = &_fcPatternElts[bi][elts];
cd2ec1a9
PL
1199 if (!nep)
1200 return FcFalse;
212c9f43 1201
cd2ec1a9 1202 fcpatternelt_ptr += old->num;
212c9f43 1203
cd2ec1a9
PL
1204 for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++)
1205 {
1206 v = e->values;
4262e0b3 1207 nvp = nv_head = FcValueListSerialize(bank, FcValueListPtrU(v));
cd2ec1a9 1208 if (!FcValueListPtrU(nv_head))
4262e0b3 1209 return 0;
cd2ec1a9
PL
1210 nv = FcValueListPtrU(nvp);
1211
1212 for (;
1213 FcValueListPtrU(v);
1214 v = FcValueListPtrU(v)->next,
1215 nv = FcValueListPtrU(nv->next))
1216 {
1217
1218 if (FcValueListPtrU(FcValueListPtrU(v)->next))
1219 {
1220 nvp = FcValueListSerialize
4262e0b3 1221 (bank, FcValueListPtrU(FcValueListPtrU(v)->next));
cd2ec1a9
PL
1222 nv->next = nvp;
1223 }
1224 }
1225
1226 nep[i].values = nv_head;
7f37423d 1227 nep[i].object = e->object;
cd2ec1a9 1228 }
212c9f43
PL
1229
1230 p->elts = old->elts;
4262e0b3 1231 p->elts = FcPatternEltPtrCreateStatic(bank, elts);
cd2ec1a9 1232 p->size = old->num;
212c9f43 1233 p->num = old->num;
cd2ec1a9
PL
1234 p->ref = FC_REF_CONSTANT;
1235 return p;
212c9f43
PL
1236}
1237
7f37423d 1238void *
61571f3f 1239FcPatternUnserialize (FcCache * metadata, void *block_ptr)
212c9f43 1240{
61571f3f 1241 int bi = FcCacheBankToIndex(metadata->bank);
4262e0b3 1242 if (!FcPatternEnsureBank(bi))
212c9f43 1243 return FcFalse;
212c9f43 1244
61571f3f 1245 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata->pattern_count);
7fd7221e 1246 block_ptr = ALIGN(block_ptr, FcPattern);
81fe99fd 1247 _fcPatterns[bi] = (FcPattern *)block_ptr;
4262e0b3 1248 block_ptr = (void *)((char *)block_ptr +
61571f3f 1249 (sizeof (FcPattern) * metadata->pattern_count));
4262e0b3
PL
1250
1251 FcMemAlloc (FC_MEM_PATELT,
61571f3f 1252 sizeof (FcPatternElt) * metadata->patternelt_count);
7fd7221e 1253 block_ptr = ALIGN(block_ptr, FcPatternElt);
81fe99fd 1254 _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
4262e0b3 1255 block_ptr = (void *)((char *)block_ptr +
61571f3f 1256 (sizeof (FcPatternElt) * metadata->patternelt_count));
4262e0b3
PL
1257
1258 block_ptr = FcStrUnserialize (metadata, block_ptr);
1259 block_ptr = FcValueListUnserialize (metadata, block_ptr);
1260
7f37423d 1261 return block_ptr;
212c9f43
PL
1262}
1263
4262e0b3
PL
1264static void
1265FcValueListNewBank (void)
212c9f43 1266{
4262e0b3
PL
1267 fcvaluelist_count = 0;
1268
1269 FcCharSetNewBank();
1270 FcLangSetNewBank();
1271}
212c9f43 1272
4262e0b3
PL
1273static int
1274FcValueListNeededBytes (FcValueList *p)
1275{
1276 FcValueList *vl;
1277 int cum = 0;
212c9f43 1278
4262e0b3
PL
1279 for (vl = p;
1280 vl;
1281 vl = FcValueListPtrU(vl->next))
212c9f43 1282 {
bb6b1993
PL
1283 /* unserialize just in case */
1284 FcValue v = FcValueCanonicalize(&vl->value);
4262e0b3
PL
1285
1286 switch (v.type)
1287 {
1288 case FcTypeCharSet:
1289 cum += FcCharSetNeededBytes(v.u.c);
1290 break;
1291 case FcTypeLangSet:
1292 cum += FcLangSetNeededBytes(v.u.l);
1293 break;
1294 case FcTypeString:
1295 cum += FcStrNeededBytes(v.u.s);
1296 default:
1297 break;
1298 }
1299 fcvaluelist_count++;
1300 cum += sizeof (FcValueList);
212c9f43 1301 }
4262e0b3
PL
1302
1303 return cum;
212c9f43
PL
1304}
1305
7fd7221e
PL
1306static int
1307FcValueListNeededBytesAlign (void)
1308{
1309 return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() +
44415a07 1310 FcStrNeededBytesAlign() + fc_alignof (FcValueList);
7fd7221e
PL
1311}
1312
4262e0b3
PL
1313static FcBool
1314FcValueListEnsureBank (int bi)
212c9f43 1315{
4262e0b3
PL
1316 FcValueList **pvl;
1317
81fe99fd 1318 if (!_fcValueLists || fcvaluelist_bank_count <= bi)
4262e0b3
PL
1319 {
1320 int new_count = bi + 2, i;
1321
81fe99fd 1322 pvl = realloc (_fcValueLists, sizeof (FcValueList *) * new_count);
4262e0b3
PL
1323 if (!pvl)
1324 return FcFalse;
212c9f43 1325
4262e0b3
PL
1326 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList *) * new_count);
1327
81fe99fd 1328 _fcValueLists = pvl;
4262e0b3 1329 for (i = fcvaluelist_bank_count; i < new_count; i++)
81fe99fd 1330 _fcValueLists[i] = 0;
4262e0b3
PL
1331
1332 fcvaluelist_bank_count = new_count;
1333 }
212c9f43
PL
1334 return FcTrue;
1335}
1336
4262e0b3
PL
1337static void *
1338FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
212c9f43 1339{
4262e0b3 1340 int bi = FcCacheBankToIndex(metadata->bank);
212c9f43 1341
4262e0b3
PL
1342 if (!FcValueListEnsureBank(bi))
1343 return 0;
212c9f43 1344
4262e0b3
PL
1345 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1346 fcvaluelist_ptr = 0;
7fd7221e 1347 block_ptr = ALIGN(block_ptr, FcValueList);
81fe99fd 1348 _fcValueLists[bi] = (FcValueList *)block_ptr;
4262e0b3
PL
1349 block_ptr = (void *)((char *)block_ptr +
1350 (sizeof (FcValueList) * fcvaluelist_count));
1351 metadata->valuelist_count = fcvaluelist_count;
1352
1353 block_ptr = FcCharSetDistributeBytes(metadata, block_ptr);
1354 block_ptr = FcLangSetDistributeBytes(metadata, block_ptr);
1355
1356 return block_ptr;
212c9f43 1357}
cd2ec1a9 1358
4262e0b3
PL
1359static FcValueListPtr
1360FcValueListSerialize(int bank, FcValueList *pi)
cd2ec1a9
PL
1361{
1362 FcValueListPtr new;
1363 FcValue * v;
4262e0b3 1364 int bi = FcCacheBankToIndex(bank);
cd2ec1a9 1365
4262e0b3 1366 if (!pi)
cd2ec1a9 1367 {
4262e0b3
PL
1368 new.bank = FC_BANK_DYNAMIC;
1369 new.u.dyn = 0;
1370 return new;
cd2ec1a9
PL
1371 }
1372
81fe99fd 1373 _fcValueLists[bi][fcvaluelist_ptr] = *pi;
4262e0b3 1374 new.bank = bank;
cd2ec1a9 1375 new.u.stat = fcvaluelist_ptr++;
81fe99fd
PL
1376 _fcValueLists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
1377 v = &_fcValueLists[bi][new.u.stat].value;
cd2ec1a9
PL
1378 switch (v->type)
1379 {
1380 case FcTypeString:
4262e0b3 1381 if (v->u.s)
cd2ec1a9 1382 {
8245771d 1383 const FcChar8 * s = FcStrSerialize(bank, v->u.s);
4262e0b3 1384 if (!s)
cd2ec1a9 1385 return FcValueListPtrCreateDynamic(pi);
8245771d 1386 v->u.s_off = s - (const FcChar8 *)v;
4262e0b3 1387 v->type |= FC_STORAGE_STATIC;
cd2ec1a9
PL
1388 }
1389 break;
1390 case FcTypeMatrix:
cd2ec1a9
PL
1391 break;
1392 case FcTypeCharSet:
4262e0b3 1393 if (v->u.c)
cd2ec1a9 1394 {
4262e0b3
PL
1395 FcCharSet * c = FcCharSetSerialize(bank, (FcCharSet *)v->u.c);
1396 if (!c)
cd2ec1a9 1397 return FcValueListPtrCreateDynamic(pi);
4262e0b3
PL
1398 v->u.c_off = (char *)c - (char *)v;
1399 v->type |= FC_STORAGE_STATIC;
cd2ec1a9
PL
1400 }
1401 break;
1402 case FcTypeLangSet:
4262e0b3 1403 if (v->u.l)
cd2ec1a9 1404 {
4262e0b3
PL
1405 FcLangSet * l = FcLangSetSerialize(bank, (FcLangSet *)v->u.l);
1406 if (!l)
cd2ec1a9 1407 return FcValueListPtrCreateDynamic(pi);
4262e0b3
PL
1408 v->u.l_off = (char *)l - (char *)v;
1409 v->type |= FC_STORAGE_STATIC;
cd2ec1a9
PL
1410 }
1411 break;
1412 default:
1413 break;
1414 }
1415 return new;
1416}
1417
4262e0b3 1418static void *
61571f3f 1419FcValueListUnserialize (FcCache * metadata, void *block_ptr)
212c9f43 1420{
61571f3f 1421 int bi = FcCacheBankToIndex(metadata->bank);
212c9f43 1422
4262e0b3
PL
1423 if (!FcValueListEnsureBank(bi))
1424 return 0;
212c9f43 1425
4262e0b3 1426 FcMemAlloc (FC_MEM_VALLIST,
61571f3f 1427 sizeof (FcValueList) * metadata->valuelist_count);
7fd7221e 1428 block_ptr = ALIGN(block_ptr, FcValueList);
81fe99fd 1429 _fcValueLists[bi] = (FcValueList *)block_ptr;
4262e0b3 1430 block_ptr = (void *)((char *)block_ptr +
61571f3f 1431 (sizeof (FcValueList) * metadata->valuelist_count));
212c9f43 1432
4262e0b3
PL
1433 block_ptr = FcCharSetUnserialize(metadata, block_ptr);
1434 block_ptr = FcLangSetUnserialize(metadata, block_ptr);
1435
1436 return block_ptr;
212c9f43
PL
1437}
1438
cd2ec1a9
PL
1439FcValueListPtr
1440FcValueListPtrCreateDynamic(FcValueList * p)
1441{
1442 FcValueListPtr r;
1443
4262e0b3 1444 r.bank = FC_BANK_DYNAMIC;
cd2ec1a9
PL
1445 r.u.dyn = p;
1446 return r;
4f27c1c0 1447}
0fa680f0 1448
8245771d 1449static FcChar8 ** static_strs;
4262e0b3 1450static int static_str_bank_count = 0, fcstr_ptr, fcstr_count;
0fa680f0 1451
4262e0b3 1452static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE];
0fa680f0 1453
4262e0b3
PL
1454static void
1455FcStrNewBank (void)
0fa680f0 1456{
4262e0b3
PL
1457 int i, size;
1458 struct objectBucket *b, *next;
1459 char *name;
0fa680f0 1460
4262e0b3 1461 for (i = 0; i < OBJECT_HASH_SIZE; i++)
0fa680f0 1462 {
4262e0b3 1463 for (b = FcStrBuckets[i]; b; b = next)
0fa680f0 1464 {
4262e0b3
PL
1465 next = b->next;
1466 name = (char *) (b + 1);
1467 size = sizeof (struct objectBucket) + strlen (name) + 1;
1468 FcMemFree (FC_MEM_STATICSTR, size);
1469 free (b);
0fa680f0 1470 }
4262e0b3 1471 FcStrBuckets[i] = 0;
0fa680f0
PL
1472 }
1473
4262e0b3
PL
1474 fcstr_count = 0;
1475}
0fa680f0 1476
4262e0b3 1477static int
8245771d 1478FcStrNeededBytes (const FcChar8 * s)
4262e0b3
PL
1479{
1480 FcChar32 hash = FcStringHash ((const FcChar8 *) s);
1481 struct objectBucket **p;
1482 struct objectBucket *b;
1483 int size;
986e3597 1484 FcChar8 *const null = 0;
0fa680f0 1485
4262e0b3 1486 for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
8245771d 1487 if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
4262e0b3 1488 return 0;
8245771d 1489 size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *);
0fa680f0 1490 b = malloc (size);
0fa680f0 1491 FcMemAlloc (FC_MEM_STATICSTR, size);
4262e0b3
PL
1492 if (!b)
1493 return -1;
0fa680f0
PL
1494 b->next = 0;
1495 b->hash = hash;
8245771d 1496 strcpy ((char *) (b + 1), (char *)s);
7fd7221e
PL
1497
1498 /* Yes, the following line is convoluted. However, it is
1499 * incorrect to replace the with a memset, because the C
1500 * specification doesn't guarantee that the null pointer is
1501 * the same as the zero bit pattern. */
986e3597
PL
1502 /* Misaligned pointers are not guaranteed to work, either! */
1503 memcpy (((char *) (b + 1) + strlen((char *)s) + 1), &null, sizeof (null));
0fa680f0 1504 *p = b;
0fa680f0 1505
8245771d
PL
1506 fcstr_count += strlen((char *)s) + 1;
1507 return strlen((char *)s) + 1;
0fa680f0
PL
1508}
1509
7fd7221e
PL
1510static int
1511FcStrNeededBytesAlign (void)
1512{
44415a07 1513 return fc_alignof (char);
7fd7221e
PL
1514}
1515
0fa680f0 1516static FcBool
4262e0b3 1517FcStrEnsureBank (int bi)
0fa680f0 1518{
8245771d 1519 FcChar8 ** ss;
0fa680f0 1520
4262e0b3 1521 if (!static_strs || static_str_bank_count <= bi)
0fa680f0 1522 {
4262e0b3
PL
1523 int new_count = bi + 4, i;
1524 ss = realloc (static_strs, sizeof (const char *) * new_count);
1525 if (!ss)
1526 return FcFalse;
0fa680f0 1527
4262e0b3
PL
1528 FcMemAlloc (FC_MEM_STRING, sizeof (const char *) * (new_count-static_str_bank_count));
1529 static_strs = ss;
0fa680f0 1530
4262e0b3
PL
1531 for (i = static_str_bank_count; i < new_count; i++)
1532 static_strs[i] = 0;
1533 static_str_bank_count = new_count;
0fa680f0 1534 }
0fa680f0 1535 return FcTrue;
0fa680f0
PL
1536}
1537
4262e0b3
PL
1538static void *
1539FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
0fa680f0 1540{
4262e0b3
PL
1541 int bi = FcCacheBankToIndex(metadata->bank);
1542 if (!FcStrEnsureBank(bi))
1543 return 0;
0fa680f0 1544
4262e0b3 1545 FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
7fd7221e 1546 block_ptr = ALIGN (block_ptr, FcChar8);
8245771d 1547 static_strs[bi] = (FcChar8 *)block_ptr;
4262e0b3
PL
1548 block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
1549 metadata->str_count = fcstr_count;
1550 fcstr_ptr = 0;
0fa680f0 1551
4262e0b3 1552 return block_ptr;
0fa680f0 1553}
e1b9d091 1554
8245771d
PL
1555static const FcChar8 *
1556FcStrSerialize (int bank, const FcChar8 * s)
212c9f43 1557{
4262e0b3
PL
1558 FcChar32 hash = FcStringHash ((const FcChar8 *) s);
1559 struct objectBucket **p;
1560 struct objectBucket *b;
1561 int bi = FcCacheBankToIndex(bank);
212c9f43 1562
4262e0b3 1563 for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
8245771d 1564 if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
4262e0b3 1565 {
986e3597
PL
1566 FcChar8 * t;
1567 memcpy (&t, ((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1, sizeof (FcChar8 *));
4262e0b3
PL
1568 if (!t)
1569 {
8245771d 1570 strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
986e3597
PL
1571 t = static_strs[bi] + fcstr_ptr;
1572 memcpy ((FcChar8 *) (b + 1) + strlen((char *)s) + 1, &t, sizeof (FcChar8 *));
8245771d 1573 fcstr_ptr += strlen((char *)s) + 1;
986e3597 1574 memcpy (&t, ((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1, sizeof (FcChar8 *));
4262e0b3
PL
1575 }
1576 return t;
1577 }
1578 return 0;
212c9f43
PL
1579}
1580
4262e0b3 1581static void *
61571f3f 1582FcStrUnserialize (FcCache * metadata, void *block_ptr)
212c9f43 1583{
61571f3f 1584 int bi = FcCacheBankToIndex(metadata->bank);
4262e0b3
PL
1585 if (!FcStrEnsureBank(bi))
1586 return 0;
212c9f43 1587
61571f3f 1588 FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata->str_count);
1c5b6345 1589 block_ptr = ALIGN (block_ptr, FcChar8);
8245771d 1590 static_strs[bi] = (FcChar8 *)block_ptr;
4262e0b3 1591 block_ptr = (void *)((char *)block_ptr +
61571f3f 1592 (sizeof (char) * metadata->str_count));
e1b9d091 1593
4262e0b3 1594 return block_ptr;
e1b9d091 1595}