]> git.wh0rd.org - fontconfig.git/blame - src/fclang.c
Properly convert static charsets to dynamic charsets.
[fontconfig.git] / src / fclang.c
CommitLineData
3de8881e 1/*
793e946c 2 * $RCSId: xc/lib/fontconfig/src/fclang.c,v 1.7 2002/08/26 23:34:31 keithp Exp $
3de8881e 3 *
46b51147 4 * Copyright © 2002 Keith Packard
3de8881e
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 "fcint.h"
26
27typedef struct {
21696e5b
PL
28 const FcChar8 *lang;
29 const FcCharSet charset;
3de8881e
KP
30} FcLangCharSet;
31
793e946c
KP
32typedef struct {
33 int begin;
34 int end;
35} FcLangCharSetRange;
36
e50b9ae7 37#include "../fc-lang/fclang.h"
3de8881e 38
d8d73958
KP
39struct _FcLangSet {
40 FcChar32 map[NUM_LANG_SET_MAP];
4262e0b3 41 FcStrSet *extra;
d8d73958
KP
42};
43
44#define FcLangSetBitSet(ls, id) ((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
45#define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)
46
82f35f8b
PL
47static FcBool langsets_populated = FcFalse;
48
d8d73958
KP
49FcLangSet *
50FcFreeTypeLangSet (const FcCharSet *charset,
e50b9ae7 51 const FcChar8 *exclusiveLang)
3de8881e 52{
cd2ec1a9 53 int i, j;
e50b9ae7 54 FcChar32 missing;
e50b9ae7 55 const FcCharSet *exclusiveCharset = 0;
d8d73958 56 FcLangSet *ls;
82f35f8b
PL
57
58 if (!langsets_populated)
59 {
60 FcLangCharSetPopulate ();
61 langsets_populated = FcTrue;
62 }
3de8881e 63
e50b9ae7
KP
64 if (exclusiveLang)
65 exclusiveCharset = FcCharSetForLang (exclusiveLang);
d8d73958
KP
66 ls = FcLangSetCreate ();
67 if (!ls)
68 return 0;
3de8881e
KP
69 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
70 {
e50b9ae7
KP
71 /*
72 * Check for Han charsets to make fonts
73 * which advertise support for a single language
74 * not support other Han languages
75 */
76 if (exclusiveCharset &&
cd2ec1a9 77 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
e50b9ae7 78 {
cd2ec1a9
PL
79 if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
80 continue;
81
82 for (j = 0; j < fcLangCharSets[i].charset.num; j++)
83 if (FcCharSetGetLeaf(&fcLangCharSets[i].charset, j) !=
84 FcCharSetGetLeaf(exclusiveCharset, j))
85 continue;
e50b9ae7 86 }
3de8881e
KP
87 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
88 if (FcDebug() & FC_DBG_SCANV)
c80d2ac4
KP
89 {
90 if (missing && missing < 10)
91 {
92 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
93 charset);
94 FcChar32 ucs4;
95 FcChar32 map[FC_CHARSET_MAP_SIZE];
96 FcChar32 next;
97
0d745819 98 printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
c80d2ac4
KP
99 printf ("{");
100 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
101 ucs4 != FC_CHARSET_DONE;
102 ucs4 = FcCharSetNextPage (missed, map, &next))
103 {
104 int i, j;
105 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
106 if (map[i])
107 {
108 for (j = 0; j < 32; j++)
109 if (map[i] & (1 << j))
110 printf (" %04x", ucs4 + i * 32 + j);
111 }
112 }
113 printf (" }\n\t");
114 FcCharSetDestroy (missed);
115 }
116 else
0d745819 117 printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
c80d2ac4 118 }
e50b9ae7 119 if (!missing)
d8d73958 120 FcLangSetBitSet (ls, i);
3de8881e 121 }
e50b9ae7 122
3de8881e
KP
123 if (FcDebug() & FC_DBG_SCANV)
124 printf ("\n");
d8d73958
KP
125
126
127 return ls;
3de8881e
KP
128}
129
d8d73958 130#define FcLangEnd(c) ((c) == '-' || (c) == '\0')
3de8881e
KP
131
132FcLangResult
133FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
134{
3de8881e 135 FcChar8 c1, c2;
d8d73958
KP
136 FcLangResult result = FcLangDifferentLang;
137
3de8881e
KP
138 for (;;)
139 {
140 c1 = *s1++;
141 c2 = *s2++;
d8d73958 142
3de8881e
KP
143 c1 = FcToLower (c1);
144 c2 = FcToLower (c2);
145 if (c1 != c2)
d8d73958
KP
146 {
147 if (FcLangEnd (c1) && FcLangEnd (c2))
148 result = FcLangDifferentCountry;
149 return result;
150 }
151 else if (!c1)
152 return FcLangEqual;
153 else if (c1 == '-')
154 result = FcLangDifferentCountry;
3de8881e 155 }
3de8881e
KP
156}
157
793e946c 158/*
74a623e0 159 * Return FcTrue when super contains sub.
793e946c 160 *
74a623e0
KP
161 * super contains sub if super and sub have the same
162 * language and either the same country or one
163 * is missing the country
793e946c
KP
164 */
165
166static FcBool
74a623e0 167FcLangContains (const FcChar8 *super, const FcChar8 *sub)
793e946c
KP
168{
169 FcChar8 c1, c2;
170
171 for (;;)
172 {
74a623e0
KP
173 c1 = *super++;
174 c2 = *sub++;
793e946c
KP
175
176 c1 = FcToLower (c1);
177 c2 = FcToLower (c2);
178 if (c1 != c2)
179 {
74a623e0 180 /* see if super has a country while sub is mising one */
793e946c
KP
181 if (c1 == '-' && c2 == '\0')
182 return FcTrue;
74a623e0
KP
183 /* see if sub has a country while super is mising one */
184 if (c1 == '\0' && c2 == '-')
185 return FcTrue;
793e946c
KP
186 return FcFalse;
187 }
188 else if (!c1)
189 return FcTrue;
190 }
191}
192
3de8881e
KP
193const FcCharSet *
194FcCharSetForLang (const FcChar8 *lang)
195{
196 int i;
197 int country = -1;
82f35f8b
PL
198
199 if (!langsets_populated)
200 {
201 FcLangCharSetPopulate ();
202 langsets_populated = FcTrue;
203 }
204
3de8881e
KP
205 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
206 {
207 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
208 case FcLangEqual:
209 return &fcLangCharSets[i].charset;
210 case FcLangDifferentCountry:
211 if (country == -1)
212 country = i;
213 default:
214 break;
215 }
216 }
217 if (country == -1)
218 return 0;
b36f2a39 219 return &fcLangCharSets[country].charset;
3de8881e 220}
d8d73958
KP
221
222FcLangSet *
223FcLangSetCreate (void)
224{
225 FcLangSet *ls;
226
227 ls = malloc (sizeof (FcLangSet));
228 if (!ls)
229 return 0;
230 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
231 memset (ls->map, '\0', sizeof (ls->map));
4262e0b3 232 ls->extra = 0;
d8d73958
KP
233 return ls;
234}
235
236void
237FcLangSetDestroy (FcLangSet *ls)
238{
4262e0b3
PL
239 if (ls->extra)
240 FcStrSetDestroy (ls->extra);
d8d73958
KP
241 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
242 free (ls);
243}
244
245FcLangSet *
246FcLangSetCopy (const FcLangSet *ls)
247{
248 FcLangSet *new;
249
250 new = FcLangSetCreate ();
251 if (!new)
252 goto bail0;
253 memcpy (new->map, ls->map, sizeof (new->map));
4262e0b3 254 if (ls->extra)
d8d73958
KP
255 {
256 FcStrList *list;
257 FcChar8 *extra;
258
4262e0b3
PL
259 new->extra = FcStrSetCreate ();
260 if (!new->extra)
d8d73958
KP
261 goto bail1;
262
4262e0b3 263 list = FcStrListCreate (ls->extra);
d8d73958
KP
264 if (!list)
265 goto bail1;
266
267 while ((extra = FcStrListNext (list)))
4262e0b3 268 if (!FcStrSetAdd (new->extra, extra))
d8d73958
KP
269 {
270 FcStrListDone (list);
271 goto bail1;
272 }
273 FcStrListDone (list);
274 }
275 return new;
276bail1:
277 FcLangSetDestroy (new);
278bail0:
279 return 0;
280}
281
282static int
283FcLangSetIndex (const FcChar8 *lang)
284{
12d49d3c
CW
285 int low, high, mid = 0;
286 int cmp = 0;
793e946c 287 FcChar8 firstChar = FcToLower(lang[0]);
947afeb5 288 FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
793e946c
KP
289
290 if (firstChar < 'a')
291 {
292 low = 0;
293 high = fcLangCharSetRanges[0].begin;
294 }
295 else if(firstChar > 'z')
296 {
297 low = fcLangCharSetRanges[25].begin;
298 high = NUM_LANG_CHAR_SET - 1;
299 }
300 else
301 {
302 low = fcLangCharSetRanges[firstChar - 'a'].begin;
303 high = fcLangCharSetRanges[firstChar - 'a'].end;
304 /* no matches */
305 if (low > high)
306 return -low; /* next entry after where it would be */
307 }
d8d73958 308
d8d73958
KP
309 while (low <= high)
310 {
311 mid = (high + low) >> 1;
793e946c
KP
312 if(fcLangCharSets[mid].lang[0] != firstChar)
313 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
314 else
315 { /* fast path for resolving 2-letter languages (by far the most common) after
316 * finding the first char (probably already true because of the hash table) */
947afeb5
KP
317 cmp = fcLangCharSets[mid].lang[1] - secondChar;
318 if (cmp == 0 &&
319 (fcLangCharSets[mid].lang[2] != '\0' ||
320 lang[2] != '\0'))
793e946c 321 {
947afeb5
KP
322 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
323 lang+2);
793e946c 324 }
793e946c
KP
325 }
326 if (cmp == 0)
d8d73958
KP
327 return mid;
328 if (cmp < 0)
329 low = mid + 1;
330 else
331 high = mid - 1;
332 }
333 if (cmp < 0)
334 mid++;
335 return -(mid + 1);
336}
337
338FcBool
339FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
340{
341 int id;
342
343 id = FcLangSetIndex (lang);
344 if (id >= 0)
345 {
346 FcLangSetBitSet (ls, id);
347 return FcTrue;
348 }
4262e0b3 349 if (!ls->extra)
d8d73958 350 {
4262e0b3
PL
351 ls->extra = FcStrSetCreate ();
352 if (!ls->extra)
d8d73958
KP
353 return FcFalse;
354 }
4262e0b3 355 return FcStrSetAdd (ls->extra, lang);
d8d73958
KP
356}
357
358FcLangResult
359FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
360{
361 int id;
362 FcLangResult best, r;
363 int i;
364
365 id = FcLangSetIndex (lang);
2458a6d8
KP
366 if (id < 0)
367 id = -id - 1;
368 else if (FcLangSetBitGet (ls, id))
d8d73958 369 return FcLangEqual;
d8d73958
KP
370 best = FcLangDifferentLang;
371 for (i = id - 1; i >= 0; i--)
372 {
373 r = FcLangCompare (lang, fcLangCharSets[i].lang);
374 if (r == FcLangDifferentLang)
375 break;
376 if (FcLangSetBitGet (ls, i) && r < best)
377 best = r;
378 }
379 for (i = id; i < NUM_LANG_CHAR_SET; i++)
380 {
381 r = FcLangCompare (lang, fcLangCharSets[i].lang);
382 if (r == FcLangDifferentLang)
383 break;
384 if (FcLangSetBitGet (ls, i) && r < best)
385 best = r;
386 }
4262e0b3 387 if (ls->extra)
d8d73958 388 {
4262e0b3 389 FcStrList *list = FcStrListCreate (ls->extra);
d8d73958 390 FcChar8 *extra;
d8d73958
KP
391
392 if (list)
393 {
394 while (best > FcLangEqual && (extra = FcStrListNext (list)))
395 {
396 r = FcLangCompare (lang, extra);
397 if (r < best)
398 best = r;
399 }
400 FcStrListDone (list);
401 }
402 }
403 return best;
404}
405
406static FcLangResult
407FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
408{
409 FcStrList *list = FcStrListCreate (set);
410 FcLangResult r, best = FcLangDifferentLang;
411 FcChar8 *extra;
412
413 if (list)
414 {
415 while (best > FcLangEqual && (extra = FcStrListNext (list)))
416 {
417 r = FcLangSetHasLang (ls, extra);
418 if (r < best)
419 best = r;
420 }
421 FcStrListDone (list);
422 }
423 return best;
424}
425
426FcLangResult
427FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
428{
234397b4 429 int i, j;
d8d73958
KP
430 FcLangResult best, r;
431
432 for (i = 0; i < NUM_LANG_SET_MAP; i++)
433 if (lsa->map[i] & lsb->map[i])
434 return FcLangEqual;
435 best = FcLangDifferentLang;
234397b4
DD
436 for (j = 0; j < NUM_COUNTRY_SET; j++)
437 for (i = 0; i < NUM_LANG_SET_MAP; i++)
438 if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
439 (lsb->map[i] & fcLangCountrySets[j][i]))
440 {
441 best = FcLangDifferentCountry;
442 break;
443 }
4262e0b3 444 if (lsa->extra)
d8d73958 445 {
4262e0b3 446 r = FcLangSetCompareStrSet (lsb, lsa->extra);
d8d73958
KP
447 if (r < best)
448 best = r;
449 }
4262e0b3 450 if (best > FcLangEqual && lsb->extra)
d8d73958 451 {
4262e0b3 452 r = FcLangSetCompareStrSet (lsa, lsb->extra);
d8d73958
KP
453 if (r < best)
454 best = r;
455 }
456 return best;
457}
458
459/*
460 * Used in computing values -- mustn't allocate any storage
461 */
462FcLangSet *
463FcLangSetPromote (const FcChar8 *lang)
464{
465 static FcLangSet ls;
466 static FcStrSet strs;
467 static FcChar8 *str;
468 int id;
469
470 memset (ls.map, '\0', sizeof (ls.map));
4262e0b3 471 ls.extra = 0;
d8d73958
KP
472 id = FcLangSetIndex (lang);
473 if (id > 0)
474 {
475 FcLangSetBitSet (&ls, id);
476 }
477 else
478 {
4262e0b3 479 ls.extra = &strs;
d8d73958
KP
480 strs.num = 1;
481 strs.size = 1;
4262e0b3 482 strs.strs = &str;
47d4f950 483 strs.ref = 1;
d8d73958
KP
484 str = (FcChar8 *) lang;
485 }
486 return &ls;
487}
488
489FcChar32
490FcLangSetHash (const FcLangSet *ls)
491{
492 FcChar32 h = 0;
493 int i;
494
495 for (i = 0; i < NUM_LANG_SET_MAP; i++)
496 h ^= ls->map[i];
4262e0b3
PL
497 if (ls->extra)
498 h ^= ls->extra->num;
d8d73958
KP
499 return h;
500}
501
502FcLangSet *
503FcNameParseLangSet (const FcChar8 *string)
504{
793e946c
KP
505 FcChar8 lang[32],c;
506 int i;
d8d73958
KP
507 FcLangSet *ls;
508
509 ls = FcLangSetCreate ();
510 if (!ls)
511 goto bail0;
512
793e946c 513 for(;;)
d8d73958 514 {
793e946c 515 for(i = 0; i < 31;i++)
d8d73958 516 {
793e946c
KP
517 c = *string++;
518 if(c == '\0' || c == '|')
519 break; /* end of this code */
520 lang[i] = c;
d8d73958 521 }
793e946c
KP
522 lang[i] = '\0';
523 if (!FcLangSetAdd (ls, lang))
524 goto bail1;
525 if(c == '\0')
526 break;
d8d73958
KP
527 }
528 return ls;
529bail1:
530 FcLangSetDestroy (ls);
531bail0:
532 return 0;
533}
534
535FcBool
536FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
537{
538 int i, bit;
539 FcChar32 bits;
540 FcBool first = FcTrue;
541
542 for (i = 0; i < NUM_LANG_SET_MAP; i++)
543 {
544 if ((bits = ls->map[i]))
545 {
546 for (bit = 0; bit <= 31; bit++)
547 if (bits & (1 << bit))
548 {
549 int id = (i << 5) | bit;
550 if (!first)
551 if (!FcStrBufChar (buf, '|'))
552 return FcFalse;
553 if (!FcStrBufString (buf, fcLangCharSets[id].lang))
554 return FcFalse;
555 first = FcFalse;
556 }
557 }
558 }
4262e0b3 559 if (ls->extra)
d8d73958 560 {
4262e0b3 561 FcStrList *list = FcStrListCreate (ls->extra);
d8d73958
KP
562 FcChar8 *extra;
563
564 if (!list)
565 return FcFalse;
566 while ((extra = FcStrListNext (list)))
567 {
568 if (!first)
569 if (!FcStrBufChar (buf, '|'))
04f7d3e7
PL
570 {
571 FcStrListDone (list);
d8d73958 572 return FcFalse;
04f7d3e7 573 }
793e946c 574 if (!FcStrBufString (buf, extra))
04f7d3e7
PL
575 {
576 FcStrListDone (list);
577 return FcFalse;
578 }
d8d73958
KP
579 first = FcFalse;
580 }
581 }
582 return FcTrue;
583}
584
585FcBool
586FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
587{
588 int i;
589
590 for (i = 0; i < NUM_LANG_SET_MAP; i++)
591 {
592 if (lsa->map[i] != lsb->map[i])
593 return FcFalse;
594 }
4262e0b3 595 if (!lsa->extra && !lsb->extra)
d8d73958 596 return FcTrue;
4262e0b3
PL
597 if (lsa->extra && lsb->extra)
598 return FcStrSetEqual (lsa->extra, lsb->extra);
d8d73958
KP
599 return FcFalse;
600}
793e946c
KP
601
602static FcBool
603FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
604{
605 int id;
793e946c
KP
606 int i;
607
608 id = FcLangSetIndex (lang);
609 if (id < 0)
610 id = -id - 1;
611 else if (FcLangSetBitGet (ls, id))
612 return FcTrue;
613 /*
614 * search up and down among equal languages for a match
615 */
616 for (i = id - 1; i >= 0; i--)
617 {
618 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
619 break;
620 if (FcLangSetBitGet (ls, i) &&
621 FcLangContains (fcLangCharSets[i].lang, lang))
622 return FcTrue;
623 }
624 for (i = id; i < NUM_LANG_CHAR_SET; i++)
625 {
626 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
627 break;
628 if (FcLangSetBitGet (ls, i) &&
629 FcLangContains (fcLangCharSets[i].lang, lang))
630 return FcTrue;
631 }
4262e0b3 632 if (ls->extra)
793e946c 633 {
4262e0b3 634 FcStrList *list = FcStrListCreate (ls->extra);
793e946c 635 FcChar8 *extra;
793e946c
KP
636
637 if (list)
638 {
639 while ((extra = FcStrListNext (list)))
640 {
641 if (FcLangContains (extra, lang))
642 break;
643 }
644 FcStrListDone (list);
645 if (extra)
646 return FcTrue;
647 }
648 }
649 return FcFalse;
650}
651
652/*
653 * return FcTrue if lsa contains every language in lsb
654 */
655FcBool
656FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
657{
658 int i, j;
659 FcChar32 missing;
660
661 if (FcDebug() & FC_DBG_MATCHV)
662 {
663 printf ("FcLangSet "); FcLangSetPrint (lsa);
664 printf (" contains "); FcLangSetPrint (lsb);
665 printf ("\n");
666 }
667 /*
668 * check bitmaps for missing language support
669 */
670 for (i = 0; i < NUM_LANG_SET_MAP; i++)
671 {
672 missing = lsb->map[i] & ~lsa->map[i];
673 if (missing)
674 {
675 for (j = 0; j < 32; j++)
676 if (missing & (1 << j))
677 {
678 if (!FcLangSetContainsLang (lsa,
679 fcLangCharSets[i*32 + j].lang))
680 {
681 if (FcDebug() & FC_DBG_MATCHV)
682 printf ("\tMissing bitmap %s\n", fcLangCharSets[i*32+j].lang);
683 return FcFalse;
684 }
685 }
686 }
687 }
4262e0b3 688 if (lsb->extra)
793e946c 689 {
4262e0b3 690 FcStrList *list = FcStrListCreate (lsb->extra);
793e946c
KP
691 FcChar8 *extra;
692
693 if (list)
694 {
695 while ((extra = FcStrListNext (list)))
696 {
697 if (!FcLangSetContainsLang (lsa, extra))
698 {
699 if (FcDebug() & FC_DBG_MATCHV)
700 printf ("\tMissing string %s\n", extra);
701 break;
702 }
703 }
704 FcStrListDone (list);
705 if (extra)
706 return FcFalse;
707 }
708 }
709 return FcTrue;
710}
cd2ec1a9 711
4262e0b3
PL
712static FcLangSet ** langsets = 0;
713static int langset_bank_count = 0, langset_ptr = 0, langset_count = 0;
cd2ec1a9
PL
714
715void
4262e0b3 716FcLangSetNewBank (void)
cd2ec1a9 717{
cd2ec1a9
PL
718 langset_count = 0;
719}
720
4262e0b3
PL
721/* ideally, should only write one copy of any particular FcLangSet */
722int
723FcLangSetNeededBytes (const FcLangSet *l)
cd2ec1a9
PL
724{
725 langset_count++;
4262e0b3 726 return sizeof (FcLangSet);
cd2ec1a9
PL
727}
728
7fd7221e
PL
729int
730FcLangSetNeededBytesAlign (void)
731{
44415a07 732 return fc_alignof (FcLangSet);
7fd7221e
PL
733}
734
4262e0b3
PL
735static FcBool
736FcLangSetEnsureBank (int bi)
cd2ec1a9 737{
4262e0b3 738 if (!langsets || bi >= langset_bank_count)
cd2ec1a9 739 {
4262e0b3
PL
740 int new_count = langset_bank_count + 2;
741 int i;
742 FcLangSet** tt;
743 tt = realloc(langsets, new_count * sizeof(FcLangSet *));
744 if (!tt)
745 return FcFalse;
746
747 langsets = tt;
748 for (i = langset_bank_count; i < new_count; i++)
749 langsets[i] = 0;
750 langset_bank_count = new_count;
cd2ec1a9
PL
751 }
752
4262e0b3 753 return FcTrue;
cd2ec1a9 754}
212c9f43 755
4262e0b3
PL
756void *
757FcLangSetDistributeBytes (FcCache * metadata, void * block_ptr)
212c9f43 758{
4262e0b3
PL
759 int bi = FcCacheBankToIndex(metadata->bank);
760 if (!FcLangSetEnsureBank(bi))
761 return 0;
212c9f43 762
7fd7221e 763 block_ptr = ALIGN(block_ptr, FcLangSet);
4262e0b3
PL
764 langsets[bi] = block_ptr;
765 block_ptr = (void *)((char *)block_ptr +
766 langset_count * sizeof(FcLangSet));
767 langset_ptr = 0;
768 metadata->langset_count = langset_count;
769 return block_ptr;
212c9f43
PL
770}
771
4262e0b3
PL
772FcLangSet *
773FcLangSetSerialize(int bank, FcLangSet *l)
212c9f43 774{
4262e0b3
PL
775 int p = langset_ptr, bi = FcCacheBankToIndex(bank);
776
777 if (!l) return 0;
778
779 langsets[bi][langset_ptr] = *l;
780 langsets[bi][langset_ptr].extra = 0;
781 langset_ptr++;
782 return &langsets[bi][p];
783}
784
785void *
61571f3f 786FcLangSetUnserialize (FcCache * metadata, void *block_ptr)
4262e0b3 787{
61571f3f 788 int bi = FcCacheBankToIndex(metadata->bank);
4262e0b3
PL
789 if (!FcLangSetEnsureBank(bi))
790 return 0;
791
61571f3f 792 FcMemAlloc (FC_MEM_LANGSET, metadata->langset_count * sizeof(FcLangSet));
7fd7221e 793 block_ptr = ALIGN(block_ptr, FcLangSet);
4262e0b3
PL
794 langsets[bi] = (FcLangSet *)block_ptr;
795 block_ptr = (void *)((char *)block_ptr +
61571f3f 796 metadata->langset_count * sizeof(FcLangSet));
4262e0b3 797 return block_ptr;
212c9f43 798}