fclang.c 16.6 KB
Newer Older
1
/*
2
 * $RCSId: xc/lib/fontconfig/src/fclang.c,v 1.7 2002/08/26 23:34:31 keithp Exp $
3
 *
4
 * Copyright © 2002 Keith Packard
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include "fcint.h"

typedef struct {
28 29
    const FcChar8	*lang;
    const FcCharSet	charset;
30 31
} FcLangCharSet;

32 33 34 35 36
typedef struct {
    int begin;
    int end;
} FcLangCharSetRange;

37
#include "../fc-lang/fclang.h"
38

39 40
struct _FcLangSet {
    FcChar32	map[NUM_LANG_SET_MAP];
41
    FcStrSet	*extra;
42 43 44 45 46
};

#define FcLangSetBitSet(ls, id)	((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
#define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)

47 48
static FcBool langsets_populated = FcFalse;

49 50
FcLangSet *
FcFreeTypeLangSet (const FcCharSet  *charset, 
51
		   const FcChar8    *exclusiveLang)
52
{
53
    int		    i, j;
54 55
    FcChar32	    missing;
    const FcCharSet *exclusiveCharset = 0;
56
    FcLangSet	    *ls;
57 58 59 60 61 62

    if (!langsets_populated)
    {
        FcLangCharSetPopulate ();
        langsets_populated = FcTrue;
    }
63

64 65
    if (exclusiveLang)
	exclusiveCharset = FcCharSetForLang (exclusiveLang);
66 67 68
    ls = FcLangSetCreate ();
    if (!ls)
	return 0;
69 70
    for (i = 0; i < NUM_LANG_CHAR_SET; i++)
    {
71 72 73 74 75 76
	/*
	 * Check for Han charsets to make fonts
	 * which advertise support for a single language
	 * not support other Han languages
	 */
	if (exclusiveCharset &&
77
	    FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
78
	{
79 80 81 82 83 84 85
	    if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
		continue;

	    for (j = 0; j < fcLangCharSets[i].charset.num; j++)
		if (FcCharSetGetLeaf(&fcLangCharSets[i].charset, j) != 
		    FcCharSetGetLeaf(exclusiveCharset, j))
		    continue;
86
	}
87 88
	missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
        if (FcDebug() & FC_DBG_SCANV)
89 90 91 92 93 94 95 96 97
	{
	    if (missing && missing < 10)
	    {
		FcCharSet   *missed = FcCharSetSubtract (&fcLangCharSets[i].charset, 
							 charset);
		FcChar32    ucs4;
		FcChar32    map[FC_CHARSET_MAP_SIZE];
		FcChar32    next;

98
		printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
		printf ("{");
		for (ucs4 = FcCharSetFirstPage (missed, map, &next);
		     ucs4 != FC_CHARSET_DONE;
		     ucs4 = FcCharSetNextPage (missed, map, &next))
		{
		    int	    i, j;
		    for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
			if (map[i])
			{
			    for (j = 0; j < 32; j++)
				if (map[i] & (1 << j))
				    printf (" %04x", ucs4 + i * 32 + j);
			}
		}
		printf (" }\n\t");
		FcCharSetDestroy (missed);
	    }
	    else
117
		printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
118
	}
119
	if (!missing)
120
	    FcLangSetBitSet (ls, i);
121
    }
122

123 124
    if (FcDebug() & FC_DBG_SCANV)
	printf ("\n");
125 126 127
    
    
    return ls;
128 129
}

130
#define FcLangEnd(c)	((c) == '-' || (c) == '\0')
131 132 133 134 135

FcLangResult
FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
{
    FcChar8	    c1, c2;
136 137
    FcLangResult    result = FcLangDifferentLang;

138 139 140 141
    for (;;)
    {
	c1 = *s1++;
	c2 = *s2++;
142
	
143 144 145
	c1 = FcToLower (c1);
	c2 = FcToLower (c2);
	if (c1 != c2)
146 147 148 149 150 151 152 153 154
	{
	    if (FcLangEnd (c1) && FcLangEnd (c2))
		result = FcLangDifferentCountry;
	    return result;
	}
	else if (!c1)
	    return FcLangEqual;
	else if (c1 == '-')
	    result = FcLangDifferentCountry;
155 156 157
    }
}

158
/*
159
 * Return FcTrue when super contains sub. 
160
 *
161 162 163
 * super contains sub if super and sub have the same
 * language and either the same country or one
 * is missing the country
164 165 166
 */

static FcBool
167
FcLangContains (const FcChar8 *super, const FcChar8 *sub)
168 169 170 171 172
{
    FcChar8	    c1, c2;

    for (;;)
    {
173 174
	c1 = *super++;
	c2 = *sub++;
175 176 177 178 179
	
	c1 = FcToLower (c1);
	c2 = FcToLower (c2);
	if (c1 != c2)
	{
180
	    /* see if super has a country while sub is mising one */
181 182
	    if (c1 == '-' && c2 == '\0')
		return FcTrue;
183 184 185
	    /* see if sub has a country while super is mising one */
	    if (c1 == '\0' && c2 == '-')
		return FcTrue;
186 187 188 189 190 191 192
	    return FcFalse;
	}
	else if (!c1)
	    return FcTrue;
    }
}

193 194 195 196 197
const FcCharSet *
FcCharSetForLang (const FcChar8 *lang)
{
    int		i;
    int		country = -1;
198 199 200 201 202 203 204

    if (!langsets_populated)
    {
        FcLangCharSetPopulate ();
        langsets_populated = FcTrue;
    }

205 206 207 208 209 210 211 212 213 214 215 216 217 218
    for (i = 0; i < NUM_LANG_CHAR_SET; i++)
    {
	switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
	case FcLangEqual:
	    return &fcLangCharSets[i].charset;
	case FcLangDifferentCountry:
	    if (country == -1)
		country = i;
	default:
	    break;
	}
    }
    if (country == -1)
	return 0;
219
    return &fcLangCharSets[country].charset;
220
}
221 222 223 224 225 226 227 228 229 230 231

FcLangSet *
FcLangSetCreate (void)
{
    FcLangSet	*ls;

    ls = malloc (sizeof (FcLangSet));
    if (!ls)
	return 0;
    FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
    memset (ls->map, '\0', sizeof (ls->map));
232
    ls->extra = 0;
233 234 235 236 237 238
    return ls;
}

void
FcLangSetDestroy (FcLangSet *ls)
{
239 240
    if (ls->extra)
	FcStrSetDestroy (ls->extra);
241 242 243 244 245 246 247 248 249 250 251 252 253
    FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
    free (ls);
}

FcLangSet *
FcLangSetCopy (const FcLangSet *ls)
{
    FcLangSet	*new;

    new = FcLangSetCreate ();
    if (!new)
	goto bail0;
    memcpy (new->map, ls->map, sizeof (new->map));
254
    if (ls->extra)
255 256 257 258
    {
	FcStrList	*list;
	FcChar8		*extra;
	
259 260
	new->extra = FcStrSetCreate ();
	if (!new->extra)
261 262
	    goto bail1;

263
	list = FcStrListCreate (ls->extra);	
264 265 266 267
	if (!list)
	    goto bail1;
	
	while ((extra = FcStrListNext (list)))
268
	    if (!FcStrSetAdd (new->extra, extra))
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
	    {
		FcStrListDone (list);
		goto bail1;
	    }
	FcStrListDone (list);
    }
    return new;
bail1:
    FcLangSetDestroy (new);
bail0:
    return 0;
}

static int
FcLangSetIndex (const FcChar8 *lang)
{
285 286
    int	    low, high, mid = 0;
    int	    cmp = 0;
287
    FcChar8 firstChar = FcToLower(lang[0]); 
288
    FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
    
    if (firstChar < 'a')
    {
	low = 0;
	high = fcLangCharSetRanges[0].begin;
    }
    else if(firstChar > 'z')
    {
	low = fcLangCharSetRanges[25].begin;
	high = NUM_LANG_CHAR_SET - 1;
    }
    else
    {
	low = fcLangCharSetRanges[firstChar - 'a'].begin;
	high = fcLangCharSetRanges[firstChar - 'a'].end;
	/* no matches */
	if (low > high)
	    return -low; /* next entry after where it would be */
    }
308 309 310 311

    while (low <= high)
    {
	mid = (high + low) >> 1;
312 313 314 315 316
	if(fcLangCharSets[mid].lang[0] != firstChar)
	    cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
	else
	{   /* fast path for resolving 2-letter languages (by far the most common) after
	     * finding the first char (probably already true because of the hash table) */
317 318 319 320
	    cmp = fcLangCharSets[mid].lang[1] - secondChar;
	    if (cmp == 0 && 
		(fcLangCharSets[mid].lang[2] != '\0' || 
		 lang[2] != '\0'))
321
	    {
322 323
		cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2, 
					 lang+2);
324 325 326
	    }
	}
	if (cmp == 0)
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
	    return mid;
	if (cmp < 0)
	    low = mid + 1;
	else
	    high = mid - 1;
    }
    if (cmp < 0)
	mid++;
    return -(mid + 1);
}

FcBool
FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
{
    int	    id;

    id = FcLangSetIndex (lang);
    if (id >= 0)
    {
	FcLangSetBitSet (ls, id);
	return FcTrue;
    }
349
    if (!ls->extra)
350
    {
351 352
	ls->extra = FcStrSetCreate ();
	if (!ls->extra)
353 354
	    return FcFalse;
    }
355
    return FcStrSetAdd (ls->extra, lang);
356 357 358 359 360 361 362 363 364 365
}

FcLangResult
FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
{
    int		    id;
    FcLangResult    best, r;
    int		    i;

    id = FcLangSetIndex (lang);
366 367 368
    if (id < 0)
	id = -id - 1;
    else if (FcLangSetBitGet (ls, id))
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
	return FcLangEqual;
    best = FcLangDifferentLang;
    for (i = id - 1; i >= 0; i--)
    {
	r = FcLangCompare (lang, fcLangCharSets[i].lang);
	if (r == FcLangDifferentLang)
	    break;
	if (FcLangSetBitGet (ls, i) && r < best)
	    best = r;
    }
    for (i = id; i < NUM_LANG_CHAR_SET; i++)
    {
	r = FcLangCompare (lang, fcLangCharSets[i].lang);
	if (r == FcLangDifferentLang)
	    break;
	if (FcLangSetBitGet (ls, i) && r < best)
	    best = r;
    }
387
    if (ls->extra)
388
    {
389
	FcStrList	*list = FcStrListCreate (ls->extra);
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
	FcChar8		*extra;
	
	if (list)
	{
	    while (best > FcLangEqual && (extra = FcStrListNext (list)))
	    {
		r = FcLangCompare (lang, extra);
		if (r < best)
		    best = r;
	    }
	    FcStrListDone (list);
	}
    }
    return best;
}

static FcLangResult
FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
{
    FcStrList	    *list = FcStrListCreate (set);
    FcLangResult    r, best = FcLangDifferentLang;
    FcChar8	    *extra;

    if (list)
    {
	while (best > FcLangEqual && (extra = FcStrListNext (list)))
	{
	    r = FcLangSetHasLang (ls, extra);
	    if (r < best)
		best = r;
	}
	FcStrListDone (list);
    }
    return best;
}

FcLangResult
FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
{
429
    int		    i, j;
430 431 432 433 434 435
    FcLangResult    best, r;

    for (i = 0; i < NUM_LANG_SET_MAP; i++)
	if (lsa->map[i] & lsb->map[i])
	    return FcLangEqual;
    best = FcLangDifferentLang;
436 437 438 439 440 441 442 443
    for (j = 0; j < NUM_COUNTRY_SET; j++)
	for (i = 0; i < NUM_LANG_SET_MAP; i++)
	    if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
		(lsb->map[i] & fcLangCountrySets[j][i]))
	    {
		best = FcLangDifferentCountry;
		break;
	    }
444
    if (lsa->extra)
445
    {
446
	r = FcLangSetCompareStrSet (lsb, lsa->extra);
447 448 449
	if (r < best)
	    best = r;
    }
450
    if (best > FcLangEqual && lsb->extra)
451
    {
452
	r = FcLangSetCompareStrSet (lsa, lsb->extra);
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
	if (r < best)
	    best = r;
    }
    return best;
}

/*
 * Used in computing values -- mustn't allocate any storage
 */
FcLangSet *
FcLangSetPromote (const FcChar8 *lang)
{
    static FcLangSet	ls;
    static FcStrSet	strs;
    static FcChar8	*str;
    int			id;

    memset (ls.map, '\0', sizeof (ls.map));
471
    ls.extra = 0;
472 473 474 475 476 477 478
    id = FcLangSetIndex (lang);
    if (id > 0)
    {
	FcLangSetBitSet (&ls, id);
    }
    else
    {
479
	ls.extra = &strs;
480 481
	strs.num = 1;
	strs.size = 1;
482
	strs.strs = &str;
483
	strs.ref = 1;
484 485 486 487 488 489 490 491 492 493 494 495 496
	str = (FcChar8 *) lang;
    }
    return &ls;
}

FcChar32
FcLangSetHash (const FcLangSet *ls)
{
    FcChar32	h = 0;
    int		i;

    for (i = 0; i < NUM_LANG_SET_MAP; i++)
	h ^= ls->map[i];
497 498
    if (ls->extra)
	h ^= ls->extra->num;
499 500 501 502 503 504
    return h;
}

FcLangSet *
FcNameParseLangSet (const FcChar8 *string)
{
505 506
    FcChar8	    lang[32],c;
    int i;
507 508 509 510 511 512
    FcLangSet	    *ls;

    ls = FcLangSetCreate ();
    if (!ls)
	goto bail0;

513
    for(;;)
514
    {
515
	for(i = 0; i < 31;i++)
516
	{
517 518 519 520
	    c = *string++;
	    if(c == '\0' || c == '|')
		break; /* end of this code */
	    lang[i] = c;
521
	}
522 523 524 525 526
	lang[i] = '\0';
	if (!FcLangSetAdd (ls, lang))
	    goto bail1;
	if(c == '\0')
	    break;
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
    }
    return ls;
bail1:
    FcLangSetDestroy (ls);
bail0:
    return 0;
}

FcBool
FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
{
    int		i, bit;
    FcChar32	bits;
    FcBool	first = FcTrue;

    for (i = 0; i < NUM_LANG_SET_MAP; i++)
    {
	if ((bits = ls->map[i]))
	{
	    for (bit = 0; bit <= 31; bit++)
		if (bits & (1 << bit))
		{
		    int id = (i << 5) | bit;
		    if (!first)
			if (!FcStrBufChar (buf, '|'))
			    return FcFalse;
		    if (!FcStrBufString (buf, fcLangCharSets[id].lang))
			return FcFalse;
		    first = FcFalse;
		}
	}
    }
559
    if (ls->extra)
560
    {
561
	FcStrList   *list = FcStrListCreate (ls->extra);
562 563 564 565 566 567 568 569 570
	FcChar8	    *extra;

	if (!list)
	    return FcFalse;
	while ((extra = FcStrListNext (list)))
	{
	    if (!first)
		if (!FcStrBufChar (buf, '|'))
		    return FcFalse;
571
	    if (!FcStrBufString (buf, extra))
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
		return FcFalse;
	    first = FcFalse;
	}
    }
    return FcTrue;
}

FcBool
FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
{
    int	    i;

    for (i = 0; i < NUM_LANG_SET_MAP; i++)
    {
	if (lsa->map[i] != lsb->map[i])
	    return FcFalse;
    }
589
    if (!lsa->extra && !lsb->extra)
590
	return FcTrue;
591 592
    if (lsa->extra && lsb->extra)
	return FcStrSetEqual (lsa->extra, lsb->extra);
593 594
    return FcFalse;
}
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625

static FcBool
FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
{
    int		    id;
    int		    i;

    id = FcLangSetIndex (lang);
    if (id < 0)
	id = -id - 1;
    else if (FcLangSetBitGet (ls, id))
	return FcTrue;
    /*
     * search up and down among equal languages for a match
     */
    for (i = id - 1; i >= 0; i--)
    {
	if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
	    break;
	if (FcLangSetBitGet (ls, i) &&
	    FcLangContains (fcLangCharSets[i].lang, lang))
	    return FcTrue;
    }
    for (i = id; i < NUM_LANG_CHAR_SET; i++)
    {
	if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
	    break;
	if (FcLangSetBitGet (ls, i) &&
	    FcLangContains (fcLangCharSets[i].lang, lang))
	    return FcTrue;
    }
626
    if (ls->extra)
627
    {
628
	FcStrList	*list = FcStrListCreate (ls->extra);
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
	FcChar8		*extra;
	
	if (list)
	{
	    while ((extra = FcStrListNext (list)))
	    {
		if (FcLangContains (extra, lang))
		    break;
	    }
	    FcStrListDone (list);
    	    if (extra)
		return FcTrue;
	}
    }
    return FcFalse;
}

/*
 * return FcTrue if lsa contains every language in lsb
 */
FcBool
FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
{
    int		    i, j;
    FcChar32	    missing;

    if (FcDebug() & FC_DBG_MATCHV)
    {
	printf ("FcLangSet "); FcLangSetPrint (lsa);
	printf (" contains "); FcLangSetPrint (lsb);
	printf ("\n");
    }
    /*
     * check bitmaps for missing language support
     */
    for (i = 0; i < NUM_LANG_SET_MAP; i++)
    {
	missing = lsb->map[i] & ~lsa->map[i];
	if (missing)
	{
	    for (j = 0; j < 32; j++)
		if (missing & (1 << j)) 
		{
		    if (!FcLangSetContainsLang (lsa,
						fcLangCharSets[i*32 + j].lang))
		    {
			if (FcDebug() & FC_DBG_MATCHV)
			    printf ("\tMissing bitmap %s\n", fcLangCharSets[i*32+j].lang);
			return FcFalse;
		    }
		}
	}
    }
682
    if (lsb->extra)
683
    {
684
	FcStrList   *list = FcStrListCreate (lsb->extra);
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
	FcChar8	    *extra;

	if (list)
	{
	    while ((extra = FcStrListNext (list)))
	    {
		if (!FcLangSetContainsLang (lsa, extra))
		{
		    if (FcDebug() & FC_DBG_MATCHV)
			printf ("\tMissing string %s\n", extra);
		    break;
		}
	    }
	    FcStrListDone (list);
	    if (extra)
		return FcFalse;
	}
    }
    return FcTrue;
}
705

706 707
static FcLangSet ** langsets = 0;
static int langset_bank_count = 0, langset_ptr = 0, langset_count = 0;
708 709

void
710
FcLangSetNewBank (void)
711 712 713 714
{
    langset_count = 0;
}

715 716 717
/* ideally, should only write one copy of any particular FcLangSet */
int
FcLangSetNeededBytes (const FcLangSet *l)
718 719
{
    langset_count++;
720
    return sizeof (FcLangSet);
721 722
}

723 724 725
int
FcLangSetNeededBytesAlign (void)
{
726
    return fc_alignof (FcLangSet);
727 728
}

729 730
static FcBool
FcLangSetEnsureBank (int bi)
731
{
732
    if (!langsets || bi >= langset_bank_count)
733
    {
734 735 736 737 738 739 740 741 742 743 744
	int new_count = langset_bank_count + 2;
	int i;
	FcLangSet** tt;
	tt = realloc(langsets, new_count * sizeof(FcLangSet *));
	if (!tt)
	    return FcFalse;

	langsets = tt;
	for (i = langset_bank_count; i < new_count; i++)
	    langsets[i] = 0; 
	langset_bank_count = new_count;
745 746
    }

747
    return FcTrue;
748
}
749

750 751
void *
FcLangSetDistributeBytes (FcCache * metadata, void * block_ptr)
752
{
753 754 755
    int bi = FcCacheBankToIndex(metadata->bank);
    if (!FcLangSetEnsureBank(bi))
	return 0;
756

757
    block_ptr = ALIGN(block_ptr, FcLangSet);
758 759 760 761 762 763
    langsets[bi] = block_ptr;
    block_ptr = (void *)((char *)block_ptr +
			 langset_count * sizeof(FcLangSet));
    langset_ptr = 0;
    metadata->langset_count = langset_count;
    return block_ptr;
764 765
}

766 767
FcLangSet *
FcLangSetSerialize(int bank, FcLangSet *l)
768
{
769 770 771 772 773 774 775 776 777 778 779
    int p = langset_ptr, bi = FcCacheBankToIndex(bank);

    if (!l) return 0;

    langsets[bi][langset_ptr] = *l;
    langsets[bi][langset_ptr].extra = 0;
    langset_ptr++;
    return &langsets[bi][p];
}

void *
780
FcLangSetUnserialize (FcCache * metadata, void *block_ptr)
781
{
782
    int bi = FcCacheBankToIndex(metadata->bank);
783 784 785
    if (!FcLangSetEnsureBank(bi))
	return 0;

786
    FcMemAlloc (FC_MEM_LANGSET, metadata->langset_count * sizeof(FcLangSet));
787
    block_ptr = ALIGN(block_ptr, FcLangSet);
788 789
    langsets[bi] = (FcLangSet *)block_ptr;
    block_ptr = (void *)((char *)block_ptr +
790
			 metadata->langset_count * sizeof(FcLangSet));
791
    return block_ptr;
792
}