]> git.wh0rd.org - fontconfig.git/blob - src/fcpat.c
da1d4905539ceddf325d3b6495e863b5e81b9d7f
[fontconfig.git] / src / fcpat.c
1 /*
2 * $RCSId: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi Exp $
3 *
4 * Copyright © 2000 Keith Packard
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 "fcint.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29
30 static FcPattern ** _fcPatterns = 0;
31 static int fcpattern_bank_count = 0, fcpattern_ptr, fcpattern_count;
32 FcPatternElt ** _fcPatternElts = 0;
33 static int fcpatternelt_ptr, fcpatternelt_count;
34 FcValueList ** _fcValueLists = 0;
35 static int fcvaluelist_bank_count = 0, fcvaluelist_ptr, fcvaluelist_count;
36
37 static FcPatternEltPtr
38 FcPatternEltPtrCreateDynamic (FcPatternElt * e);
39 static FcBool
40 FcStrHashed (const FcChar8 *name);
41
42 FcPattern *
43 FcPatternCreate (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;
53 p->elts = FcPatternEltPtrCreateDynamic(0);
54 p->bank = FC_BANK_DYNAMIC;
55 p->ref = 1;
56 return p;
57 }
58
59 void
60 FcValueDestroy (FcValue v)
61 {
62 switch (v.type) {
63 case FcTypeString:
64 if (!FcStrHashed (v.u.s))
65 FcStrFree ((FcChar8 *) v.u.s);
66 break;
67 case FcTypeMatrix:
68 FcMatrixFree ((FcMatrix *) v.u.m);
69 break;
70 case FcTypeCharSet:
71 FcCharSetDestroy ((FcCharSet *) v.u.c);
72 break;
73 case FcTypeLangSet:
74 FcLangSetDestroy ((FcLangSet *) v.u.l);
75 break;
76 default:
77 break;
78 }
79 }
80
81 FcValue
82 FcValueCanonicalize (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
108 FcValue
109 FcValueSave (FcValue v)
110 {
111 switch (v.type) {
112 case FcTypeString:
113 v.u.s = FcStrCopy (v.u.s);
114 if (!v.u.s)
115 v.type = FcTypeVoid;
116 break;
117 case FcTypeMatrix:
118 v.u.m = FcMatrixCopy (v.u.m);
119 if (!v.u.m)
120 v.type = FcTypeVoid;
121 break;
122 case FcTypeCharSet:
123 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
124 if (!v.u.c)
125 v.type = FcTypeVoid;
126 break;
127 case FcTypeLangSet:
128 v.u.l = FcLangSetCopy (v.u.l);
129 if (!v.u.l)
130 v.type = FcTypeVoid;
131 break;
132 default:
133 break;
134 }
135 return v;
136 }
137
138 void
139 FcValueListDestroy (FcValueListPtr l)
140 {
141 FcValueListPtr next;
142 for (; FcValueListPtrU(l); l = next)
143 {
144 switch (FcValueListPtrU(l)->value.type) {
145 case FcTypeString:
146 if (!FcStrHashed ((FcChar8 *)FcValueListPtrU(l)->value.u.s))
147 FcStrFree ((FcChar8 *)FcValueListPtrU(l)->value.u.s);
148 break;
149 case FcTypeMatrix:
150 FcMatrixFree ((FcMatrix *)FcValueListPtrU(l)->value.u.m);
151 break;
152 case FcTypeCharSet:
153 FcCharSetDestroy
154 ((FcCharSet *) (FcValueListPtrU(l)->value.u.c));
155 break;
156 case FcTypeLangSet:
157 FcLangSetDestroy
158 ((FcLangSet *) (FcValueListPtrU(l)->value.u.l));
159 break;
160 default:
161 break;
162 }
163 next = FcValueListPtrU(l)->next;
164 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
165 if (l.bank == FC_BANK_DYNAMIC)
166 free(l.u.dyn);
167 }
168 }
169
170 FcBool
171 FcValueEqual (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:
196 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
197 case FcTypeBool:
198 return va.u.b == vb.u.b;
199 case FcTypeMatrix:
200 return FcMatrixEqual (va.u.m, vb.u.m);
201 case FcTypeCharSet:
202 return FcCharSetEqual (va.u.c, vb.u.c);
203 case FcTypeFTFace:
204 return va.u.f == vb.u.f;
205 case FcTypeLangSet:
206 return FcLangSetEqual (va.u.l, vb.u.l);
207 }
208 return FcFalse;
209 }
210
211 static FcChar32
212 FcDoubleHash (double d)
213 {
214 if (d < 0)
215 d = -d;
216 if (d > 0xffffffff)
217 d = 0xffffffff;
218 return (FcChar32) d;
219 }
220
221 FcChar32
222 FcStringHash (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
233 static FcChar32
234 FcValueHash (const FcValue *v)
235 {
236 switch (fc_storage_type(v)) {
237 case FcTypeVoid:
238 return 0;
239 case FcTypeInteger:
240 return (FcChar32) v->u.i;
241 case FcTypeDouble:
242 return FcDoubleHash (v->u.d);
243 case FcTypeString:
244 return FcStringHash (fc_value_string(v));
245 case FcTypeBool:
246 return (FcChar32) v->u.b;
247 case FcTypeMatrix:
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));
252 case FcTypeCharSet:
253 return (FcChar32) fc_value_charset(v)->num;
254 case FcTypeFTFace:
255 return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
256 FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
257 case FcTypeLangSet:
258 return FcLangSetHash (fc_value_langset(v));
259 }
260 return FcFalse;
261 }
262
263 static FcBool
264 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
265 {
266 if (FcValueListPtrU(la) == FcValueListPtrU(lb))
267 return FcTrue;
268
269 while (FcValueListPtrU(la) && FcValueListPtrU(lb))
270 {
271 if (!FcValueEqual (FcValueListPtrU(la)->value,
272 FcValueListPtrU(lb)->value))
273 return FcFalse;
274 la = FcValueListPtrU(la)->next;
275 lb = FcValueListPtrU(lb)->next;
276 }
277 if (FcValueListPtrU(la) || FcValueListPtrU(lb))
278 return FcFalse;
279 return FcTrue;
280 }
281
282 static FcChar32
283 FcValueListHash (FcValueListPtr l)
284 {
285 FcChar32 hash = 0;
286 FcValueList *l_ptrU;
287
288 for (l_ptrU = FcValueListPtrU(l); l_ptrU;
289 l_ptrU = FcValueListPtrU(l_ptrU->next))
290 {
291 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l_ptrU->value);
292 }
293 return hash;
294 }
295
296 void
297 FcPatternDestroy (FcPattern *p)
298 {
299 int i;
300
301 if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
302 return;
303
304 for (i = 0; i < p->num; i++)
305 FcValueListDestroy ((FcPatternEltU(p->elts)+i)->values);
306
307 p->num = 0;
308 if (FcPatternEltU(p->elts) && p->elts.bank == FC_BANK_DYNAMIC)
309 {
310 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
311 free (FcPatternEltU(p->elts));
312 p->elts = FcPatternEltPtrCreateDynamic(0);
313 }
314 p->size = 0;
315 FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
316 free (p);
317 }
318
319 static int
320 FcPatternPosition (const FcPattern *p, const char *object)
321 {
322 int low, high, mid, c;
323 FcObjectPtr obj;
324
325 obj = FcObjectToPtr(object);
326 low = 0;
327 high = p->num - 1;
328 c = 1;
329 mid = 0;
330 while (low <= high)
331 {
332 mid = (low + high) >> 1;
333 c = FcObjectPtrCompare((FcPatternEltU(p->elts)+mid)->object, obj);
334 if (c == 0)
335 return mid;
336 if (c < 0)
337 low = mid + 1;
338 else
339 high = mid - 1;
340 }
341 if (c < 0)
342 mid++;
343 return -(mid + 1);
344 }
345
346 FcPatternElt *
347 FcPatternFindElt (const FcPattern *p, const char *object)
348 {
349 int i = FcPatternPosition (p, object);
350 if (i < 0)
351 return 0;
352 return FcPatternEltU(p->elts)+i;
353 }
354
355 FcPatternElt *
356 FcPatternInsertElt (FcPattern *p, const char *object)
357 {
358 int i;
359 FcPatternElt *e;
360
361 i = FcPatternPosition (p, object);
362 if (i < 0)
363 {
364 i = -i - 1;
365
366 /* reallocate array */
367 if (p->num + 1 >= p->size)
368 {
369 int s = p->size + 16;
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 }
381 else
382 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
383 if (!e)
384 return FcFalse;
385 p->elts = FcPatternEltPtrCreateDynamic(e);
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 {
391 (FcPatternEltU(p->elts)+p->size)->object = 0;
392 (FcPatternEltU(p->elts)+p->size)->values =
393 FcValueListPtrCreateDynamic(0);
394 p->size++;
395 }
396 }
397
398 /* move elts up */
399 memmove (FcPatternEltU(p->elts) + i + 1,
400 FcPatternEltU(p->elts) + i,
401 sizeof (FcPatternElt) *
402 (p->num - i));
403
404 /* bump count */
405 p->num++;
406
407 (FcPatternEltU(p->elts)+i)->object = FcObjectToPtr (object);
408 (FcPatternEltU(p->elts)+i)->values = FcValueListPtrCreateDynamic(0);
409 }
410
411 return FcPatternEltU(p->elts)+i;
412 }
413
414 FcBool
415 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
416 {
417 int i;
418
419 if (pa == pb)
420 return FcTrue;
421
422 if (pa->num != pb->num)
423 return FcFalse;
424 for (i = 0; i < pa->num; i++)
425 {
426 if (FcObjectPtrCompare((FcPatternEltU(pa->elts)+i)->object,
427 (FcPatternEltU(pb->elts)+i)->object) != 0)
428 return FcFalse;
429 if (!FcValueListEqual ((FcPatternEltU(pa->elts)+i)->values,
430 (FcPatternEltU(pb->elts)+i)->values))
431 return FcFalse;
432 }
433 return FcTrue;
434 }
435
436 FcChar32
437 FcPatternHash (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)) ^
445 FcStringHash ((FcChar8 *)FcObjectPtrU ((FcPatternEltU(p->elts)+i)->object)) ^
446 FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
447 }
448 return h;
449 }
450
451 FcBool
452 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
453 {
454 FcPatternElt *ea, *eb;
455 int i;
456
457 for (i = 0; i < os->nobject; i++)
458 {
459 ea = FcPatternFindElt (pai, os->objects[i]);
460 eb = FcPatternFindElt (pbi, os->objects[i]);
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
477 FcBool
478 FcPatternAddWithBinding (FcPattern *p,
479 const char *object,
480 FcValue value,
481 FcValueBinding binding,
482 FcBool append)
483 {
484 FcPatternElt *e;
485 FcValueListPtr new, *prev;
486 FcValueList *newp;
487 FcObjectPtr objectPtr;
488
489 if (p->ref == FC_REF_CONSTANT)
490 goto bail0;
491
492 newp = malloc (sizeof (FcValueList));
493 if (!newp)
494 goto bail0;
495
496 memset(newp, 0, sizeof (FcValueList));
497 new = FcValueListPtrCreateDynamic(newp);
498 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
499 /* dup string */
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);
508 if (value.type == FcTypeVoid)
509 goto bail1;
510
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.
517 * a better hack would use FcBaseObjectTypes to check all objects. */
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)
527 goto bail1;
528
529 FcValueListPtrU(new)->value = value;
530 FcValueListPtrU(new)->binding = binding;
531 FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
532
533 e = FcPatternInsertElt (p, object);
534 if (!e)
535 goto bail2;
536
537 if (append)
538 {
539 for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
540 ;
541 *prev = new;
542 }
543 else
544 {
545 FcValueListPtrU(new)->next = e->values;
546 e->values = new;
547 }
548
549 return FcTrue;
550
551 bail2:
552 switch (value.type) {
553 case FcTypeString:
554 FcStrFree ((FcChar8 *) value.u.s);
555 break;
556 case FcTypeMatrix:
557 FcMatrixFree ((FcMatrix *) value.u.m);
558 break;
559 case FcTypeCharSet:
560 FcCharSetDestroy ((FcCharSet *) value.u.c);
561 break;
562 case FcTypeLangSet:
563 FcLangSetDestroy ((FcLangSet *) value.u.l);
564 break;
565 default:
566 break;
567 }
568 bail1:
569 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
570 free (FcValueListPtrU(new));
571 bail0:
572 return FcFalse;
573 }
574
575 FcBool
576 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
577 {
578 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
579 }
580
581 FcBool
582 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
583 {
584 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
585 }
586
587 FcBool
588 FcPatternDel (FcPattern *p, const char *object)
589 {
590 FcPatternElt *e;
591
592 e = FcPatternFindElt (p, object);
593 if (!e)
594 return FcFalse;
595
596 /* destroy value */
597 FcValueListDestroy (e->values);
598
599 /* shuffle existing ones down */
600 memmove (e, e+1,
601 (FcPatternEltU(p->elts) + p->num - (e + 1)) *
602 sizeof (FcPatternElt));
603 p->num--;
604 (FcPatternEltU(p->elts)+p->num)->object = 0;
605 (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
606 return FcTrue;
607 }
608
609 FcBool
610 FcPatternRemove (FcPattern *p, const char *object, int id)
611 {
612 FcPatternElt *e;
613 FcValueListPtr *prev, l;
614
615 e = FcPatternFindElt (p, object);
616 if (!e)
617 return FcFalse;
618 for (prev = &e->values;
619 FcValueListPtrU(l = *prev);
620 prev = &FcValueListPtrU(l)->next)
621 {
622 if (!id)
623 {
624 *prev = FcValueListPtrU(l)->next;
625 FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
626 FcValueListDestroy (l);
627 if (!FcValueListPtrU(e->values))
628 FcPatternDel (p, object);
629 return FcTrue;
630 }
631 id--;
632 }
633 return FcFalse;
634 }
635
636 FcBool
637 FcPatternAddInteger (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
646 FcBool
647 FcPatternAddDouble (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
657 FcBool
658 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
659 {
660 FcValue v;
661
662 if (!s)
663 {
664 v.type = FcTypeVoid;
665 v.u.s = 0;
666 return FcPatternAdd (p, object, v, FcTrue);
667 }
668
669 v.type = FcTypeString;
670 v.u.s = FcStrStaticName(s);
671 return FcPatternAdd (p, object, v, FcTrue);
672 }
673
674 FcBool
675 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
676 {
677 FcValue v;
678
679 v.type = FcTypeMatrix;
680 v.u.m = s;
681 return FcPatternAdd (p, object, v, FcTrue);
682 }
683
684
685 FcBool
686 FcPatternAddBool (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
695 FcBool
696 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
697 {
698 FcValue v;
699
700 v.type = FcTypeCharSet;
701 v.u.c = (FcCharSet *)c;
702 return FcPatternAdd (p, object, v, FcTrue);
703 }
704
705 FcBool
706 FcPatternAddFTFace (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
715 FcBool
716 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
717 {
718 FcValue v;
719
720 v.type = FcTypeLangSet;
721 v.u.l = (FcLangSet *)ls;
722 return FcPatternAdd (p, object, v, FcTrue);
723 }
724
725 FcResult
726 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
727 {
728 FcPatternElt *e;
729 FcValueListPtr l;
730
731 e = FcPatternFindElt (p, object);
732 if (!e)
733 return FcResultNoMatch;
734 for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
735 {
736 if (!id)
737 {
738 *v = FcValueCanonicalize(&FcValueListPtrU(l)->value);
739 return FcResultMatch;
740 }
741 id--;
742 }
743 return FcResultNoId;
744 }
745
746 FcResult
747 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
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
768 FcResult
769 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
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
790 FcResult
791 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
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;
801
802 *s = (FcChar8 *) v.u.s;
803 return FcResultMatch;
804 }
805
806 FcResult
807 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
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;
817 *m = (FcMatrix *)v.u.m;
818 return FcResultMatch;
819 }
820
821
822 FcResult
823 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
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
837 FcResult
838 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
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;
848 *c = (FcCharSet *)v.u.c;
849 return FcResultMatch;
850 }
851
852 FcResult
853 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
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
867 FcResult
868 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
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;
878 *ls = (FcLangSet *)v.u.l;
879 return FcResultMatch;
880 }
881
882 FcPattern *
883 FcPatternDuplicate (const FcPattern *orig)
884 {
885 FcPattern *new;
886 FcPatternElt *e;
887 int i;
888 FcValueListPtr l;
889
890 new = FcPatternCreate ();
891 if (!new)
892 goto bail0;
893
894 e = FcPatternEltU(orig->elts);
895
896 for (i = 0; i < orig->num; i++)
897 {
898 for (l = (e + i)->values;
899 FcValueListPtrU(l);
900 l = FcValueListPtrU(l)->next)
901 if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object),
902 FcValueCanonicalize(&FcValueListPtrU(l)->value),
903 FcTrue))
904 goto bail1;
905 }
906
907 return new;
908
909 bail1:
910 FcPatternDestroy (new);
911 bail0:
912 return 0;
913 }
914
915 void
916 FcPatternReference (FcPattern *p)
917 {
918 if (p->ref != FC_REF_CONSTANT)
919 p->ref++;
920 }
921
922 FcPattern *
923 FcPatternVaBuild (FcPattern *orig, va_list va)
924 {
925 FcPattern *ret;
926
927 FcPatternVapBuild (ret, orig, va);
928 return ret;
929 }
930
931 FcPattern *
932 FcPatternBuild (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 }
941
942 /*
943 * Add all of the elements in 's' to 'p'
944 */
945 FcBool
946 FcPatternAppend (FcPattern *p, FcPattern *s)
947 {
948 int i;
949 FcPatternElt *e;
950 FcValueListPtr v;
951
952 for (i = 0; i < s->num; i++)
953 {
954 e = FcPatternEltU(s->elts)+i;
955 for (v = e->values; FcValueListPtrU(v);
956 v = FcValueListPtrU(v)->next)
957 {
958 if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
959 FcValueCanonicalize(&FcValueListPtrU(v)->value),
960 FcValueListPtrU(v)->binding, FcTrue))
961 return FcFalse;
962 }
963 }
964 return FcTrue;
965 }
966
967 #define OBJECT_HASH_SIZE 31
968 static struct objectBucket {
969 struct objectBucket *next;
970 FcChar32 hash;
971 } *FcObjectBuckets[OBJECT_HASH_SIZE];
972
973 static FcBool
974 FcStrHashed (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
986 const FcChar8 *
987 FcStrStaticName (const FcChar8 *name)
988 {
989 FcChar32 hash = FcStringHash (name);
990 struct objectBucket **p;
991 struct objectBucket *b;
992 int size;
993
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;
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));
1001 if (!b)
1002 return NULL;
1003 b->next = 0;
1004 b->hash = hash;
1005 strcpy ((char *) (b + 1), (char *)name);
1006 *p = b;
1007 return (FcChar8 *) (b + 1);
1008 }
1009
1010 static void
1011 FcStrStaticNameFini (void)
1012 {
1013 int i, size;
1014 struct objectBucket *b, *next;
1015 char *name;
1016
1017 for (i = 0; i < OBJECT_HASH_SIZE; i++)
1018 {
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;
1028 }
1029 }
1030
1031 void
1032 FcPatternFini (void)
1033 {
1034 FcStrStaticNameFini ();
1035 FcObjectStaticNameFini ();
1036 }
1037
1038 static FcPatternEltPtr
1039 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1040 {
1041 FcPatternEltPtr new;
1042 new.bank = FC_BANK_DYNAMIC;
1043 new.u.dyn = e;
1044 return new;
1045 }
1046
1047 static FcPatternEltPtr
1048 FcPatternEltPtrCreateStatic (int bank, int i)
1049 {
1050 FcPatternEltPtr new;
1051 new.bank = bank;
1052 new.u.stat = i;
1053 return new;
1054 }
1055
1056 static void
1057 FcStrNewBank (void);
1058 static int
1059 FcStrNeededBytes (const FcChar8 * s);
1060 static int
1061 FcStrNeededBytesAlign (void);
1062 static void *
1063 FcStrDistributeBytes (FcCache * metadata, void * block_ptr);
1064 static const FcChar8 *
1065 FcStrSerialize (int bank, const FcChar8 * s);
1066 static void *
1067 FcStrUnserialize (FcCache * metadata, void *block_ptr);
1068
1069 static void
1070 FcValueListNewBank (void);
1071 static int
1072 FcValueListNeededBytes (FcValueList * vl);
1073 static int
1074 FcValueListNeededBytesAlign (void);
1075 static void *
1076 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr);
1077 static FcValueListPtr
1078 FcValueListSerialize(int bank, FcValueList *pi);
1079 static void *
1080 FcValueListUnserialize (FcCache * metadata, void *block_ptr);
1081
1082
1083 void
1084 FcPatternNewBank (void)
1085 {
1086 fcpattern_count = 0;
1087 fcpatternelt_count = 0;
1088
1089 FcStrNewBank();
1090 FcValueListNewBank();
1091 }
1092
1093 int
1094 FcPatternNeededBytes (FcPattern * p)
1095 {
1096 int i, cum = 0, c;
1097
1098 fcpattern_count++;
1099 fcpatternelt_count += p->num;
1100
1101 for (i = 0; i < p->num; i++)
1102 {
1103 c = FcValueListNeededBytes (FcValueListPtrU
1104 (((FcPatternEltU(p->elts)+i)->values)));
1105 if (c < 0)
1106 return c;
1107 cum += c;
1108 }
1109
1110 return cum + sizeof (FcPattern) + sizeof(FcPatternElt)*p->num;
1111 }
1112
1113 int
1114 FcPatternNeededBytesAlign (void)
1115 {
1116 return fc_alignof (FcPattern) + fc_alignof (FcPatternElt) +
1117 FcValueListNeededBytesAlign ();
1118 }
1119
1120 static FcBool
1121 FcPatternEnsureBank (int bi)
1122 {
1123 FcPattern **pp;
1124 FcPatternElt **ep;
1125 int i;
1126
1127 if (!_fcPatterns || fcpattern_bank_count <= bi)
1128 {
1129 int new_count = bi + 4;
1130 pp = realloc (_fcPatterns, sizeof (FcPattern *) * new_count);
1131 if (!pp)
1132 return 0;
1133
1134 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern *) * new_count);
1135 _fcPatterns = pp;
1136
1137 ep = realloc (_fcPatternElts, sizeof (FcPatternElt *) * new_count);
1138 if (!ep)
1139 return 0;
1140
1141 FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt *) * new_count);
1142 _fcPatternElts = ep;
1143
1144 for (i = fcpattern_bank_count; i < new_count; i++)
1145 {
1146 _fcPatterns[i] = 0;
1147 _fcPatternElts[i] = 0;
1148 }
1149
1150 fcpattern_bank_count = new_count;
1151 }
1152
1153 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
1154 return FcTrue;
1155 }
1156
1157 void *
1158 FcPatternDistributeBytes (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;
1166 block_ptr = ALIGN(block_ptr, FcPattern);
1167 _fcPatterns[bi] = (FcPattern *)block_ptr;
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;
1173 block_ptr = ALIGN(block_ptr, FcPatternElt);
1174 _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
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
1186 FcPattern *
1187 FcPatternSerialize (int bank, FcPattern *old)
1188 {
1189 FcPattern *p;
1190 FcPatternElt *e, *nep;
1191 FcValueList * nv;
1192 FcValueListPtr v, nv_head, nvp;
1193 int i, elts, bi = FcCacheBankToIndex(bank);
1194
1195 p = &_fcPatterns[bi][fcpattern_ptr++];
1196 p->bank = bank;
1197 elts = fcpatternelt_ptr;
1198 nep = &_fcPatternElts[bi][elts];
1199 if (!nep)
1200 return FcFalse;
1201
1202 fcpatternelt_ptr += old->num;
1203
1204 for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++)
1205 {
1206 v = e->values;
1207 nvp = nv_head = FcValueListSerialize(bank, FcValueListPtrU(v));
1208 if (!FcValueListPtrU(nv_head))
1209 return 0;
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
1221 (bank, FcValueListPtrU(FcValueListPtrU(v)->next));
1222 nv->next = nvp;
1223 }
1224 }
1225
1226 nep[i].values = nv_head;
1227 nep[i].object = e->object;
1228 }
1229
1230 p->elts = old->elts;
1231 p->elts = FcPatternEltPtrCreateStatic(bank, elts);
1232 p->size = old->num;
1233 p->num = old->num;
1234 p->ref = FC_REF_CONSTANT;
1235 return p;
1236 }
1237
1238 void *
1239 FcPatternUnserialize (FcCache * metadata, void *block_ptr)
1240 {
1241 int bi = FcCacheBankToIndex(metadata->bank);
1242 if (!FcPatternEnsureBank(bi))
1243 return FcFalse;
1244
1245 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * metadata->pattern_count);
1246 block_ptr = ALIGN(block_ptr, FcPattern);
1247 _fcPatterns[bi] = (FcPattern *)block_ptr;
1248 block_ptr = (void *)((char *)block_ptr +
1249 (sizeof (FcPattern) * metadata->pattern_count));
1250
1251 FcMemAlloc (FC_MEM_PATELT,
1252 sizeof (FcPatternElt) * metadata->patternelt_count);
1253 block_ptr = ALIGN(block_ptr, FcPatternElt);
1254 _fcPatternElts[bi] = (FcPatternElt *)block_ptr;
1255 block_ptr = (void *)((char *)block_ptr +
1256 (sizeof (FcPatternElt) * metadata->patternelt_count));
1257
1258 block_ptr = FcStrUnserialize (metadata, block_ptr);
1259 block_ptr = FcValueListUnserialize (metadata, block_ptr);
1260
1261 return block_ptr;
1262 }
1263
1264 static void
1265 FcValueListNewBank (void)
1266 {
1267 fcvaluelist_count = 0;
1268
1269 FcCharSetNewBank();
1270 FcLangSetNewBank();
1271 }
1272
1273 static int
1274 FcValueListNeededBytes (FcValueList *p)
1275 {
1276 FcValueList *vl;
1277 int cum = 0;
1278
1279 for (vl = p;
1280 vl;
1281 vl = FcValueListPtrU(vl->next))
1282 {
1283 /* unserialize just in case */
1284 FcValue v = FcValueCanonicalize(&vl->value);
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);
1301 }
1302
1303 return cum;
1304 }
1305
1306 static int
1307 FcValueListNeededBytesAlign (void)
1308 {
1309 return FcCharSetNeededBytesAlign() + FcLangSetNeededBytesAlign() +
1310 FcStrNeededBytesAlign() + fc_alignof (FcValueList);
1311 }
1312
1313 static FcBool
1314 FcValueListEnsureBank (int bi)
1315 {
1316 FcValueList **pvl;
1317
1318 if (!_fcValueLists || fcvaluelist_bank_count <= bi)
1319 {
1320 int new_count = bi + 2, i;
1321
1322 pvl = realloc (_fcValueLists, sizeof (FcValueList *) * new_count);
1323 if (!pvl)
1324 return FcFalse;
1325
1326 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList *) * new_count);
1327
1328 _fcValueLists = pvl;
1329 for (i = fcvaluelist_bank_count; i < new_count; i++)
1330 _fcValueLists[i] = 0;
1331
1332 fcvaluelist_bank_count = new_count;
1333 }
1334 return FcTrue;
1335 }
1336
1337 static void *
1338 FcValueListDistributeBytes (FcCache * metadata, void *block_ptr)
1339 {
1340 int bi = FcCacheBankToIndex(metadata->bank);
1341
1342 if (!FcValueListEnsureBank(bi))
1343 return 0;
1344
1345 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1346 fcvaluelist_ptr = 0;
1347 block_ptr = ALIGN(block_ptr, FcValueList);
1348 _fcValueLists[bi] = (FcValueList *)block_ptr;
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;
1357 }
1358
1359 static FcValueListPtr
1360 FcValueListSerialize(int bank, FcValueList *pi)
1361 {
1362 FcValueListPtr new;
1363 FcValue * v;
1364 int bi = FcCacheBankToIndex(bank);
1365
1366 if (!pi)
1367 {
1368 new.bank = FC_BANK_DYNAMIC;
1369 new.u.dyn = 0;
1370 return new;
1371 }
1372
1373 _fcValueLists[bi][fcvaluelist_ptr] = *pi;
1374 new.bank = bank;
1375 new.u.stat = fcvaluelist_ptr++;
1376 _fcValueLists[bi][new.u.stat].value = FcValueCanonicalize (&pi->value);
1377 v = &_fcValueLists[bi][new.u.stat].value;
1378 switch (v->type)
1379 {
1380 case FcTypeString:
1381 if (v->u.s)
1382 {
1383 const FcChar8 * s = FcStrSerialize(bank, v->u.s);
1384 if (!s)
1385 return FcValueListPtrCreateDynamic(pi);
1386 v->u.s_off = s - (const FcChar8 *)v;
1387 v->type |= FC_STORAGE_STATIC;
1388 }
1389 break;
1390 case FcTypeMatrix:
1391 break;
1392 case FcTypeCharSet:
1393 if (v->u.c)
1394 {
1395 FcCharSet * c = FcCharSetSerialize(bank, (FcCharSet *)v->u.c);
1396 if (!c)
1397 return FcValueListPtrCreateDynamic(pi);
1398 v->u.c_off = (char *)c - (char *)v;
1399 v->type |= FC_STORAGE_STATIC;
1400 }
1401 break;
1402 case FcTypeLangSet:
1403 if (v->u.l)
1404 {
1405 FcLangSet * l = FcLangSetSerialize(bank, (FcLangSet *)v->u.l);
1406 if (!l)
1407 return FcValueListPtrCreateDynamic(pi);
1408 v->u.l_off = (char *)l - (char *)v;
1409 v->type |= FC_STORAGE_STATIC;
1410 }
1411 break;
1412 default:
1413 break;
1414 }
1415 return new;
1416 }
1417
1418 static void *
1419 FcValueListUnserialize (FcCache * metadata, void *block_ptr)
1420 {
1421 int bi = FcCacheBankToIndex(metadata->bank);
1422
1423 if (!FcValueListEnsureBank(bi))
1424 return 0;
1425
1426 FcMemAlloc (FC_MEM_VALLIST,
1427 sizeof (FcValueList) * metadata->valuelist_count);
1428 block_ptr = ALIGN(block_ptr, FcValueList);
1429 _fcValueLists[bi] = (FcValueList *)block_ptr;
1430 block_ptr = (void *)((char *)block_ptr +
1431 (sizeof (FcValueList) * metadata->valuelist_count));
1432
1433 block_ptr = FcCharSetUnserialize(metadata, block_ptr);
1434 block_ptr = FcLangSetUnserialize(metadata, block_ptr);
1435
1436 return block_ptr;
1437 }
1438
1439 FcValueListPtr
1440 FcValueListPtrCreateDynamic(FcValueList * p)
1441 {
1442 FcValueListPtr r;
1443
1444 r.bank = FC_BANK_DYNAMIC;
1445 r.u.dyn = p;
1446 return r;
1447 }
1448
1449 static FcChar8 ** static_strs;
1450 static int static_str_bank_count = 0, fcstr_ptr, fcstr_count;
1451
1452 static struct objectBucket *FcStrBuckets[OBJECT_HASH_SIZE];
1453
1454 static void
1455 FcStrNewBank (void)
1456 {
1457 int i, size;
1458 struct objectBucket *b, *next;
1459 char *name;
1460
1461 for (i = 0; i < OBJECT_HASH_SIZE; i++)
1462 {
1463 for (b = FcStrBuckets[i]; b; b = next)
1464 {
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);
1470 }
1471 FcStrBuckets[i] = 0;
1472 }
1473
1474 fcstr_count = 0;
1475 }
1476
1477 static int
1478 FcStrNeededBytes (const FcChar8 * s)
1479 {
1480 FcChar32 hash = FcStringHash ((const FcChar8 *) s);
1481 struct objectBucket **p;
1482 struct objectBucket *b;
1483 int size;
1484 FcChar8 *const null = 0;
1485
1486 for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1487 if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1488 return 0;
1489 size = sizeof (struct objectBucket) + strlen ((char *)s) + 1 + sizeof(char *);
1490 b = malloc (size);
1491 FcMemAlloc (FC_MEM_STATICSTR, size);
1492 if (!b)
1493 return -1;
1494 b->next = 0;
1495 b->hash = hash;
1496 strcpy ((char *) (b + 1), (char *)s);
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. */
1502 /* Misaligned pointers are not guaranteed to work, either! */
1503 memcpy (((char *) (b + 1) + strlen((char *)s) + 1), &null, sizeof (null));
1504 *p = b;
1505
1506 fcstr_count += strlen((char *)s) + 1;
1507 return strlen((char *)s) + 1;
1508 }
1509
1510 static int
1511 FcStrNeededBytesAlign (void)
1512 {
1513 return fc_alignof (char);
1514 }
1515
1516 static FcBool
1517 FcStrEnsureBank (int bi)
1518 {
1519 FcChar8 ** ss;
1520
1521 if (!static_strs || static_str_bank_count <= bi)
1522 {
1523 int new_count = bi + 4, i;
1524 ss = realloc (static_strs, sizeof (const char *) * new_count);
1525 if (!ss)
1526 return FcFalse;
1527
1528 FcMemAlloc (FC_MEM_STRING, sizeof (const char *) * (new_count-static_str_bank_count));
1529 static_strs = ss;
1530
1531 for (i = static_str_bank_count; i < new_count; i++)
1532 static_strs[i] = 0;
1533 static_str_bank_count = new_count;
1534 }
1535 return FcTrue;
1536 }
1537
1538 static void *
1539 FcStrDistributeBytes (FcCache * metadata, void * block_ptr)
1540 {
1541 int bi = FcCacheBankToIndex(metadata->bank);
1542 if (!FcStrEnsureBank(bi))
1543 return 0;
1544
1545 FcMemAlloc (FC_MEM_STRING, sizeof (char) * fcstr_count);
1546 block_ptr = ALIGN (block_ptr, FcChar8);
1547 static_strs[bi] = (FcChar8 *)block_ptr;
1548 block_ptr = (void *)((char *)block_ptr + (sizeof (char) * fcstr_count));
1549 metadata->str_count = fcstr_count;
1550 fcstr_ptr = 0;
1551
1552 return block_ptr;
1553 }
1554
1555 static const FcChar8 *
1556 FcStrSerialize (int bank, const FcChar8 * s)
1557 {
1558 FcChar32 hash = FcStringHash ((const FcChar8 *) s);
1559 struct objectBucket **p;
1560 struct objectBucket *b;
1561 int bi = FcCacheBankToIndex(bank);
1562
1563 for (p = &FcStrBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1564 if (b->hash == hash && !strcmp ((char *)s, (char *) (b + 1)))
1565 {
1566 FcChar8 * t;
1567 memcpy (&t, ((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1, sizeof (FcChar8 *));
1568 if (!t)
1569 {
1570 strcpy((char *)(static_strs[bi] + fcstr_ptr), (char *)s);
1571 t = static_strs[bi] + fcstr_ptr;
1572 memcpy ((FcChar8 *) (b + 1) + strlen((char *)s) + 1, &t, sizeof (FcChar8 *));
1573 fcstr_ptr += strlen((char *)s) + 1;
1574 memcpy (&t, ((FcChar8 *)(b + 1)) + strlen ((char *)s) + 1, sizeof (FcChar8 *));
1575 }
1576 return t;
1577 }
1578 return 0;
1579 }
1580
1581 static void *
1582 FcStrUnserialize (FcCache * metadata, void *block_ptr)
1583 {
1584 int bi = FcCacheBankToIndex(metadata->bank);
1585 if (!FcStrEnsureBank(bi))
1586 return 0;
1587
1588 FcMemAlloc (FC_MEM_STRING, sizeof (char) * metadata->str_count);
1589 block_ptr = ALIGN (block_ptr, FcChar8);
1590 static_strs[bi] = (FcChar8 *)block_ptr;
1591 block_ptr = (void *)((char *)block_ptr +
1592 (sizeof (char) * metadata->str_count));
1593
1594 return block_ptr;
1595 }