1 /*
2  * fontconfig/src/fcstr.c
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 the author(s) not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  The authors make 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  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE AUTHOR(S) 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 <ctype.h>
28 #include <string.h>
29 
30 
31 /* Objects MT-safe for readonly access. */
32 
33 FcChar8 *
FcStrCopy(const FcChar8 * s)34 FcStrCopy (const FcChar8 *s)
35 {
36     return FcStrdup (s);
37 }
38 
39 static FcChar8 *
FcStrMakeTriple(const FcChar8 * s1,const FcChar8 * s2,const FcChar8 * s3)40 FcStrMakeTriple (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *s3)
41 {
42     int	    s1l = s1 ? strlen ((char *) s1) : 0;
43     int	    s2l = s2 ? strlen ((char *) s2) : 0;
44     int     s3l = s3 ? strlen ((char *) s3) : 0;
45     int	    l = s1l + 1 + s2l + 1 + s3l + 1;
46     FcChar8 *s = malloc (l);
47 
48     if (!s)
49 	return 0;
50     if (s1)
51 	memcpy (s, s1, s1l + 1);
52     else
53 	s[0] = '\0';
54     if (s2)
55 	memcpy (s + s1l + 1, s2, s2l + 1);
56     else
57 	s[s1l + 1] = '\0';
58     if (s3)
59 	memcpy (s + s1l + 1 + s2l + 1, s3, s3l + 1);
60     else
61 	s[s1l + 1 + s2l + 1] = '\0';
62     return s;
63 }
64 
65 FcChar8 *
FcStrPlus(const FcChar8 * s1,const FcChar8 * s2)66 FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
67 {
68     int	    s1l = strlen ((char *) s1);
69     int	    s2l = strlen ((char *) s2);
70     int	    l = s1l + s2l + 1;
71     FcChar8 *s = malloc (l);
72 
73     if (!s)
74 	return 0;
75     memcpy (s, s1, s1l);
76     memcpy (s + s1l, s2, s2l + 1);
77     return s;
78 }
79 
80 void
FcStrFree(FcChar8 * s)81 FcStrFree (FcChar8 *s)
82 {
83     free (s);
84 }
85 
86 
87 #include "../fc-case/fccase.h"
88 
89 #define FcCaseFoldUpperCount(cf) \
90     ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
91 
92 typedef struct _FcCaseWalker {
93     const FcChar8   *read;
94     const FcChar8   *src;
95     FcChar8	    utf8[FC_MAX_CASE_FOLD_CHARS + 1];
96 } FcCaseWalker;
97 
98 static void
FcStrCaseWalkerInit(const FcChar8 * src,FcCaseWalker * w)99 FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w)
100 {
101     w->src = src;
102     w->read = 0;
103 }
104 
105 static FcChar8
FcStrCaseWalkerLong(FcCaseWalker * w,FcChar8 r)106 FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
107 {
108     FcChar32	ucs4;
109     int		slen;
110     int		len = strlen((char*)w->src);
111 
112     slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1);
113     if (slen <= 0)
114 	return r;
115     if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR)
116     {
117 	int min = 0;
118 	int max = FC_NUM_CASE_FOLD;
119 
120 	while (min <= max)
121 	{
122 	    int		mid = (min + max) >> 1;
123 	    FcChar32    low = fcCaseFold[mid].upper;
124 	    FcChar32    high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]);
125 
126 	    if (high <= ucs4)
127 		min = mid + 1;
128 	    else if (ucs4 < low)
129 		max = mid - 1;
130 	    else
131 	    {
132 		const FcCaseFold    *fold = &fcCaseFold[mid];
133 		int		    dlen;
134 
135 		switch (fold->method) {
136 		case  FC_CASE_FOLD_EVEN_ODD:
137 		    if ((ucs4 & 1) != (fold->upper & 1))
138 			return r;
139 		    /* fall through ... */
140 		default:
141 		    dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8);
142 		    break;
143 		case FC_CASE_FOLD_FULL:
144 		    dlen = fold->count;
145 		    memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen);
146 		    break;
147 		}
148 
149 		/* consume rest of src utf-8 bytes */
150 		w->src += slen - 1;
151 
152 		/* read from temp buffer */
153 		w->utf8[dlen] = '\0';
154 		w->read = w->utf8;
155 		return *w->read++;
156 	    }
157 	}
158     }
159     return r;
160 }
161 
162 static FcChar8
FcStrCaseWalkerNextNonDelim(FcCaseWalker * w,const char * delims)163 FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims)
164 {
165     FcChar8	r;
166 
167     if (FC_UNLIKELY (w->read != NULL))
168     {
169 	if ((r = *w->read++))
170 	    return r;
171 	w->read = 0;
172     }
173     do
174     {
175 	r = *w->src++;
176     } while (r != 0 && delims && strchr (delims, r));
177 
178     if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
179 	return FcStrCaseWalkerLong (w, r);
180     if ('A' <= r && r <= 'Z')
181         r = r - 'A' + 'a';
182     return r;
183 }
184 
185 static FcChar8
FcStrCaseWalkerNextNonBlank(FcCaseWalker * w)186 FcStrCaseWalkerNextNonBlank (FcCaseWalker *w)
187 {
188     FcChar8	r;
189 
190     if (FC_UNLIKELY (w->read != NULL))
191     {
192 	if ((r = *w->read++))
193 	    return r;
194 	w->read = 0;
195     }
196     do
197     {
198 	r = *w->src++;
199     } while (r == ' ');
200 
201     if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
202 	return FcStrCaseWalkerLong (w, r);
203     if ('A' <= r && r <= 'Z')
204         r = r - 'A' + 'a';
205     return r;
206 }
207 
208 static FcChar8
FcStrCaseWalkerNext(FcCaseWalker * w)209 FcStrCaseWalkerNext (FcCaseWalker *w)
210 {
211     FcChar8	r;
212 
213     if (FC_UNLIKELY (w->read != NULL))
214     {
215 	if ((r = *w->read++))
216 	    return r;
217 	w->read = 0;
218     }
219 
220     r = *w->src++;
221 
222     if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
223 	return FcStrCaseWalkerLong (w, r);
224     if ('A' <= r && r <= 'Z')
225         r = r - 'A' + 'a';
226     return r;
227 }
228 
229 FcChar8 *
FcStrDowncase(const FcChar8 * s)230 FcStrDowncase (const FcChar8 *s)
231 {
232     FcCaseWalker    w;
233     int		    len = 0;
234     FcChar8	    *dst, *d;
235 
236     FcStrCaseWalkerInit (s, &w);
237     while (FcStrCaseWalkerNext (&w))
238 	len++;
239     d = dst = malloc (len + 1);
240     if (!d)
241 	return 0;
242     FcStrCaseWalkerInit (s, &w);
243     while ((*d++ = FcStrCaseWalkerNext (&w)));
244     return dst;
245 }
246 
247 int
FcStrCmpIgnoreCase(const FcChar8 * s1,const FcChar8 * s2)248 FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
249 {
250     FcCaseWalker    w1, w2;
251     FcChar8	    c1, c2;
252 
253     if (s1 == s2) return 0;
254 
255     FcStrCaseWalkerInit (s1, &w1);
256     FcStrCaseWalkerInit (s2, &w2);
257 
258     for (;;)
259     {
260 	c1 = FcStrCaseWalkerNext (&w1);
261 	c2 = FcStrCaseWalkerNext (&w2);
262 	if (!c1 || (c1 != c2))
263 	    break;
264     }
265     return (int) c1 - (int) c2;
266 }
267 
268 int
FcStrCmpIgnoreBlanksAndCase(const FcChar8 * s1,const FcChar8 * s2)269 FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
270 {
271     FcCaseWalker    w1, w2;
272     FcChar8	    c1, c2;
273 
274     if (s1 == s2) return 0;
275 
276     FcStrCaseWalkerInit (s1, &w1);
277     FcStrCaseWalkerInit (s2, &w2);
278 
279     for (;;)
280     {
281 	c1 = FcStrCaseWalkerNextNonBlank (&w1);
282 	c2 = FcStrCaseWalkerNextNonBlank (&w2);
283 	if (!c1 || (c1 != c2))
284 	    break;
285     }
286     return (int) c1 - (int) c2;
287 }
288 
289 int
FcStrCmp(const FcChar8 * s1,const FcChar8 * s2)290 FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
291 {
292     FcChar8 c1, c2;
293 
294     if (s1 == s2)
295 	return 0;
296     for (;;)
297     {
298 	c1 = *s1++;
299 	c2 = *s2++;
300 	if (!c1 || c1 != c2)
301 	    break;
302     }
303     return (int) c1 - (int) c2;
304 }
305 
306 /*
307  * Return a hash value for a string
308  */
309 
310 FcChar32
FcStrHashIgnoreCase(const FcChar8 * s)311 FcStrHashIgnoreCase (const FcChar8 *s)
312 {
313     FcChar32	    h = 0;
314     FcCaseWalker    w;
315     FcChar8	    c;
316 
317     FcStrCaseWalkerInit (s, &w);
318     while ((c = FcStrCaseWalkerNext (&w)))
319 	h = ((h << 3) ^ (h >> 3)) ^ c;
320     return h;
321 }
322 
323 FcChar32
FcStrHashIgnoreBlanksAndCase(const FcChar8 * s)324 FcStrHashIgnoreBlanksAndCase (const FcChar8 *s)
325 {
326     FcChar32	    h = 0;
327     FcCaseWalker    w;
328     FcChar8	    c;
329 
330     FcStrCaseWalkerInit (s, &w);
331     while ((c = FcStrCaseWalkerNextNonBlank (&w)))
332 	h = ((h << 3) ^ (h >> 3)) ^ c;
333     return h;
334 }
335 
336 /*
337  * Is the head of s1 equal to s2?
338  */
339 
340 static FcBool
FcStrIsAtIgnoreBlanksAndCase(const FcChar8 * s1,const FcChar8 * s2)341 FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
342 {
343     FcCaseWalker    w1, w2;
344     FcChar8	    c1, c2;
345 
346     FcStrCaseWalkerInit (s1, &w1);
347     FcStrCaseWalkerInit (s2, &w2);
348 
349     for (;;)
350     {
351 	c1 = FcStrCaseWalkerNextNonBlank (&w1);
352 	c2 = FcStrCaseWalkerNextNonBlank (&w2);
353 	if (!c1 || (c1 != c2))
354 	    break;
355     }
356     return c1 == c2 || !c2;
357 }
358 
359 /*
360  * Does s1 contain an instance of s2 (ignoring blanks and case)?
361  */
362 
363 const FcChar8 *
FcStrContainsIgnoreBlanksAndCase(const FcChar8 * s1,const FcChar8 * s2)364 FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
365 {
366     while (*s1)
367     {
368 	if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
369 	    return s1;
370 	s1++;
371     }
372     return 0;
373 }
374 
375 static FcBool
FcCharIsPunct(const FcChar8 c)376 FcCharIsPunct (const FcChar8 c)
377 {
378     if (c < '0')
379 	return FcTrue;
380     if (c <= '9')
381 	return FcFalse;
382     if (c < 'A')
383 	return FcTrue;
384     if (c <= 'Z')
385 	return FcFalse;
386     if (c < 'a')
387 	return FcTrue;
388     if (c <= 'z')
389 	return FcFalse;
390     if (c <= '~')
391 	return FcTrue;
392     return FcFalse;
393 }
394 
395 /*
396  * Is the head of s1 equal to s2?
397  */
398 
399 static FcBool
FcStrIsAtIgnoreCase(const FcChar8 * s1,const FcChar8 * s2)400 FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
401 {
402     FcCaseWalker    w1, w2;
403     FcChar8	    c1, c2;
404 
405     FcStrCaseWalkerInit (s1, &w1);
406     FcStrCaseWalkerInit (s2, &w2);
407 
408     for (;;)
409     {
410 	c1 = FcStrCaseWalkerNext (&w1);
411 	c2 = FcStrCaseWalkerNext (&w2);
412 	if (!c1 || (c1 != c2))
413 	    break;
414     }
415     return c1 == c2 || !c2;
416 }
417 
418 /*
419  * Does s1 contain an instance of s2 (ignoring blanks and case)?
420  */
421 
422 const FcChar8 *
FcStrContainsIgnoreCase(const FcChar8 * s1,const FcChar8 * s2)423 FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
424 {
425     while (*s1)
426     {
427 	if (FcStrIsAtIgnoreCase (s1, s2))
428 	    return s1;
429 	s1++;
430     }
431     return 0;
432 }
433 
434 /*
435  * Does s1 contain an instance of s2 on a word boundary (ignoring case)?
436  */
437 
438 const FcChar8 *
FcStrContainsWord(const FcChar8 * s1,const FcChar8 * s2)439 FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2)
440 {
441     FcBool  wordStart = FcTrue;
442     int	    s1len = strlen ((char *) s1);
443     int	    s2len = strlen ((char *) s2);
444 
445     while (s1len >= s2len)
446     {
447 	if (wordStart &&
448 	    FcStrIsAtIgnoreCase (s1, s2) &&
449 	    (s1len == s2len || FcCharIsPunct (s1[s2len])))
450 	{
451 	    return s1;
452 	}
453 	wordStart = FcFalse;
454 	if (FcCharIsPunct (*s1))
455 	    wordStart = FcTrue;
456 	s1++;
457 	s1len--;
458     }
459     return 0;
460 }
461 
462 /*
463  * returns the number of strings (ignoring delimiters and case) being matched
464  */
465 
466 int
FcStrMatchIgnoreCaseAndDelims(const FcChar8 * s1,const FcChar8 * s2,const FcChar8 * delims)467 FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims)
468 {
469     FcCaseWalker    w1, w2;
470     FcChar8	    c1, c2;
471 
472     if (s1 == s2) return 0;
473 
474     FcStrCaseWalkerInit (s1, &w1);
475     FcStrCaseWalkerInit (s2, &w2);
476 
477     for (;;)
478     {
479 	c1 = FcStrCaseWalkerNextNonDelim (&w1, (const char *)delims);
480 	c2 = FcStrCaseWalkerNextNonDelim (&w2, (const char *)delims);
481 	if (!c1 || (c1 != c2))
482 	    break;
483     }
484     return w1.src - s1 - 1;
485 }
486 
487 FcBool
FcStrGlobMatch(const FcChar8 * glob,const FcChar8 * string)488 FcStrGlobMatch (const FcChar8 *glob,
489 		const FcChar8 *string)
490 {
491     FcChar8	c;
492 
493     while ((c = *glob++))
494     {
495 	switch (c) {
496 	case '*':
497 	    /* short circuit common case */
498 	    if (!*glob)
499 		return FcTrue;
500 	    /* short circuit another common case */
501 	    if (strchr ((char *) glob, '*') == 0)
502 	    {
503 		size_t l1, l2;
504 
505 		l1 = strlen ((char *) string);
506 		l2 = strlen ((char *) glob);
507 		if (l1 < l2)
508 		    return FcFalse;
509 		string += (l1 - l2);
510 	    }
511 	    while (*string)
512 	    {
513 		if (FcStrGlobMatch (glob, string))
514 		    return FcTrue;
515 		string++;
516 	    }
517 	    return FcFalse;
518 	case '?':
519 	    if (*string++ == '\0')
520 		return FcFalse;
521 	    break;
522 	default:
523 	    if (*string++ != c)
524 		return FcFalse;
525 	    break;
526 	}
527     }
528     return *string == '\0';
529 }
530 
531 const FcChar8 *
FcStrStrIgnoreCase(const FcChar8 * s1,const FcChar8 * s2)532 FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
533 {
534     FcCaseWalker    w1, w2;
535     FcChar8	    c1, c2;
536     const FcChar8   *cur;
537 
538     if (!s1 || !s2)
539 	return 0;
540 
541     if (s1 == s2)
542 	return s1;
543 
544     FcStrCaseWalkerInit (s1, &w1);
545     FcStrCaseWalkerInit (s2, &w2);
546 
547     c2 = FcStrCaseWalkerNext (&w2);
548 
549     for (;;)
550     {
551 	cur = w1.src;
552 	c1 = FcStrCaseWalkerNext (&w1);
553 	if (!c1)
554 	    break;
555 	if (c1 == c2)
556 	{
557 	    FcCaseWalker    w1t = w1;
558 	    FcCaseWalker    w2t = w2;
559 	    FcChar8	    c1t, c2t;
560 
561 	    for (;;)
562 	    {
563 		c1t = FcStrCaseWalkerNext (&w1t);
564 		c2t = FcStrCaseWalkerNext (&w2t);
565 
566 		if (!c2t)
567 		    return cur;
568 		if (c2t != c1t)
569 		    break;
570 	    }
571 	}
572     }
573     return 0;
574 }
575 
576 const FcChar8 *
FcStrStr(const FcChar8 * s1,const FcChar8 * s2)577 FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
578 {
579     FcChar8 c1, c2;
580     const FcChar8 * p = s1;
581     const FcChar8 * b = s2;
582 
583     if (!s1 || !s2)
584 	return 0;
585 
586     if (s1 == s2)
587 	return s1;
588 
589 again:
590     c2 = *s2++;
591 
592     if (!c2)
593 	return 0;
594 
595     for (;;)
596     {
597 	p = s1;
598 	c1 = *s1++;
599 	if (!c1 || c1 == c2)
600 	    break;
601     }
602 
603     if (c1 != c2)
604 	return 0;
605 
606     for (;;)
607     {
608 	c1 = *s1;
609 	c2 = *s2;
610 	if (c1 && c2 && c1 != c2)
611 	{
612 	    s1 = p + 1;
613 	    s2 = b;
614 	    goto again;
615 	}
616 	if (!c2)
617 	    return p;
618 	if (!c1)
619 	    return 0;
620 	++ s1;
621 	++ s2;
622     }
623     /* never reached. */
624 }
625 
626 int
FcUtf8ToUcs4(const FcChar8 * src_orig,FcChar32 * dst,int len)627 FcUtf8ToUcs4 (const FcChar8 *src_orig,
628 	      FcChar32	    *dst,
629 	      int	    len)
630 {
631     const FcChar8   *src = src_orig;
632     FcChar8	    s;
633     int		    extra;
634     FcChar32	    result;
635 
636     if (len == 0)
637 	return 0;
638 
639     s = *src++;
640     len--;
641 
642     if (!(s & 0x80))
643     {
644 	result = s;
645 	extra = 0;
646     }
647     else if (!(s & 0x40))
648     {
649 	return -1;
650     }
651     else if (!(s & 0x20))
652     {
653 	result = s & 0x1f;
654 	extra = 1;
655     }
656     else if (!(s & 0x10))
657     {
658 	result = s & 0xf;
659 	extra = 2;
660     }
661     else if (!(s & 0x08))
662     {
663 	result = s & 0x07;
664 	extra = 3;
665     }
666     else if (!(s & 0x04))
667     {
668 	result = s & 0x03;
669 	extra = 4;
670     }
671     else if ( ! (s & 0x02))
672     {
673 	result = s & 0x01;
674 	extra = 5;
675     }
676     else
677     {
678 	return -1;
679     }
680     if (extra > len)
681 	return -1;
682 
683     while (extra--)
684     {
685 	result <<= 6;
686 	s = *src++;
687 
688 	if ((s & 0xc0) != 0x80)
689 	    return -1;
690 
691 	result |= s & 0x3f;
692     }
693     *dst = result;
694     return src - src_orig;
695 }
696 
697 FcBool
FcUtf8Len(const FcChar8 * string,int len,int * nchar,int * wchar)698 FcUtf8Len (const FcChar8    *string,
699 	   int		    len,
700 	   int		    *nchar,
701 	   int		    *wchar)
702 {
703     int		n;
704     int		clen;
705     FcChar32	c;
706     FcChar32	max;
707 
708     n = 0;
709     max = 0;
710     while (len)
711     {
712 	clen = FcUtf8ToUcs4 (string, &c, len);
713 	if (clen <= 0)	/* malformed UTF8 string */
714 	    return FcFalse;
715 	if (c > max)
716 	    max = c;
717 	string += clen;
718 	len -= clen;
719 	n++;
720     }
721     *nchar = n;
722     if (max >= 0x10000)
723 	*wchar = 4;
724     else if (max > 0x100)
725 	*wchar = 2;
726     else
727 	*wchar = 1;
728     return FcTrue;
729 }
730 
731 int
FcUcs4ToUtf8(FcChar32 ucs4,FcChar8 dest[FC_UTF8_MAX_LEN])732 FcUcs4ToUtf8 (FcChar32	ucs4,
733 	      FcChar8	dest[FC_UTF8_MAX_LEN])
734 {
735     int	bits;
736     FcChar8 *d = dest;
737 
738     if      (ucs4 <       0x80) {  *d++=  ucs4;                         bits= -6; }
739     else if (ucs4 <      0x800) {  *d++= ((ucs4 >>  6) & 0x1F) | 0xC0;  bits=  0; }
740     else if (ucs4 <    0x10000) {  *d++= ((ucs4 >> 12) & 0x0F) | 0xE0;  bits=  6; }
741     else if (ucs4 <   0x200000) {  *d++= ((ucs4 >> 18) & 0x07) | 0xF0;  bits= 12; }
742     else if (ucs4 <  0x4000000) {  *d++= ((ucs4 >> 24) & 0x03) | 0xF8;  bits= 18; }
743     else if (ucs4 < 0x80000000) {  *d++= ((ucs4 >> 30) & 0x01) | 0xFC;  bits= 24; }
744     else return 0;
745 
746     for ( ; bits >= 0; bits-= 6) {
747 	*d++= ((ucs4 >> bits) & 0x3F) | 0x80;
748     }
749     return d - dest;
750 }
751 
752 #define GetUtf16(src,endian) \
753     ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
754      (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
755 
756 int
FcUtf16ToUcs4(const FcChar8 * src_orig,FcEndian endian,FcChar32 * dst,int len)757 FcUtf16ToUcs4 (const FcChar8	*src_orig,
758 	       FcEndian		endian,
759 	       FcChar32		*dst,
760 	       int		len)	/* in bytes */
761 {
762     const FcChar8   *src = src_orig;
763     FcChar16	    a, b;
764     FcChar32	    result;
765 
766     if (len < 2)
767 	return 0;
768 
769     a = GetUtf16 (src, endian); src += 2; len -= 2;
770 
771     /*
772      * Check for surrogate
773      */
774     if ((a & 0xfc00) == 0xd800)
775     {
776 	if (len < 2)
777 	    return 0;
778 	b = GetUtf16 (src, endian); src += 2; len -= 2;
779 	/*
780 	 * Check for invalid surrogate sequence
781 	 */
782 	if ((b & 0xfc00) != 0xdc00)
783 	    return 0;
784 	result = ((((FcChar32) a & 0x3ff) << 10) |
785 		  ((FcChar32) b & 0x3ff)) + 0x10000;
786     }
787     else
788 	result = a;
789     *dst = result;
790     return src - src_orig;
791 }
792 
793 FcBool
FcUtf16Len(const FcChar8 * string,FcEndian endian,int len,int * nchar,int * wchar)794 FcUtf16Len (const FcChar8   *string,
795 	    FcEndian	    endian,
796 	    int		    len,	/* in bytes */
797 	    int		    *nchar,
798 	    int		    *wchar)
799 {
800     int		n;
801     int		clen;
802     FcChar32	c;
803     FcChar32	max;
804 
805     n = 0;
806     max = 0;
807     while (len)
808     {
809 	clen = FcUtf16ToUcs4 (string, endian, &c, len);
810 	if (clen <= 0)	/* malformed UTF8 string */
811 	    return FcFalse;
812 	if (c > max)
813 	    max = c;
814 	string += clen;
815 	len -= clen;
816 	n++;
817     }
818     *nchar = n;
819     if (max >= 0x10000)
820 	*wchar = 4;
821     else if (max > 0x100)
822 	*wchar = 2;
823     else
824 	*wchar = 1;
825     return FcTrue;
826 }
827 
828 void
FcStrBufInit(FcStrBuf * buf,FcChar8 * init,int size)829 FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
830 {
831     if (init)
832     {
833 	buf->buf = init;
834 	buf->size = size;
835     } else
836     {
837 	buf->buf = buf->buf_static;
838 	buf->size = sizeof (buf->buf_static);
839     }
840     buf->allocated = FcFalse;
841     buf->failed = FcFalse;
842     buf->len = 0;
843 }
844 
845 void
FcStrBufDestroy(FcStrBuf * buf)846 FcStrBufDestroy (FcStrBuf *buf)
847 {
848     if (buf->allocated)
849     {
850 	free (buf->buf);
851 	FcStrBufInit (buf, 0, 0);
852     }
853 }
854 
855 FcChar8 *
FcStrBufDone(FcStrBuf * buf)856 FcStrBufDone (FcStrBuf *buf)
857 {
858     FcChar8 *ret;
859 
860     if (buf->failed)
861 	ret = NULL;
862     else
863 	ret = malloc (buf->len + 1);
864     if (ret)
865     {
866 	memcpy (ret, buf->buf, buf->len);
867 	ret[buf->len] = '\0';
868     }
869     FcStrBufDestroy (buf);
870     return ret;
871 }
872 
873 FcChar8 *
FcStrBufDoneStatic(FcStrBuf * buf)874 FcStrBufDoneStatic (FcStrBuf *buf)
875 {
876     FcStrBufChar (buf, '\0');
877 
878     if (buf->failed)
879 	return NULL;
880 
881     return buf->buf;
882 }
883 
884 FcBool
FcStrBufChar(FcStrBuf * buf,FcChar8 c)885 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
886 {
887     if (buf->len == buf->size)
888     {
889 	FcChar8	    *new;
890 	int	    size;
891 
892 	if (buf->failed)
893 	    return FcFalse;
894 
895 	if (buf->allocated)
896 	{
897 	    size = buf->size * 2;
898 	    new = realloc (buf->buf, size);
899 	}
900 	else
901 	{
902 	    size = buf->size + 64;
903 	    new = malloc (size);
904 	    if (new)
905 	    {
906 		buf->allocated = FcTrue;
907 		memcpy (new, buf->buf, buf->len);
908 	    }
909 	}
910 	if (!new)
911 	{
912 	    buf->failed = FcTrue;
913 	    return FcFalse;
914 	}
915 	buf->size = size;
916 	buf->buf = new;
917     }
918     buf->buf[buf->len++] = c;
919     return FcTrue;
920 }
921 
922 FcBool
FcStrBufString(FcStrBuf * buf,const FcChar8 * s)923 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
924 {
925     FcChar8 c;
926     while ((c = *s++))
927 	if (!FcStrBufChar (buf, c))
928 	    return FcFalse;
929     return FcTrue;
930 }
931 
932 FcBool
FcStrBufData(FcStrBuf * buf,const FcChar8 * s,int len)933 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
934 {
935     while (len-- > 0)
936 	if (!FcStrBufChar (buf, *s++))
937 	    return FcFalse;
938     return FcTrue;
939 }
940 
941 FcBool
FcStrUsesHome(const FcChar8 * s)942 FcStrUsesHome (const FcChar8 *s)
943 {
944     return *s == '~';
945 }
946 
947 FcBool
FcStrIsAbsoluteFilename(const FcChar8 * s)948 FcStrIsAbsoluteFilename (const FcChar8 *s)
949 {
950 #ifdef _WIN32
951     if (*s == '\\' ||
952 	(isalpha (*s) && s[1] == ':' && (s[2] == '/' || s[2] == '\\')))
953 	return FcTrue;
954 #endif
955     return *s == '/';
956 }
957 
958 FcChar8 *
FcStrBuildFilename(const FcChar8 * path,...)959 FcStrBuildFilename (const FcChar8 *path,
960 		    ...)
961 {
962     va_list ap;
963     FcStrSet *sset;
964     FcStrList *list;
965     FcChar8 *s, *ret = NULL, *p;
966     size_t len = 0;
967 
968     if (!path)
969 	return NULL;
970 
971     sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64);
972     if (!sset)
973 	return NULL;
974 
975     if (!FcStrSetAdd (sset, path))
976 	goto bail0;
977 
978     va_start (ap, path);
979     while (1)
980     {
981 	s = (FcChar8 *)va_arg (ap, FcChar8 *);
982 	if (!s)
983 	    break;
984 	if (!FcStrSetAdd (sset, s))
985 	    goto bail1;
986     }
987     list = FcStrListCreate (sset);
988     while ((s = FcStrListNext (list)))
989     {
990 	len += strlen ((const char *)s) + 1;
991     }
992     list->n = 0;
993     ret = malloc (sizeof (FcChar8) * (len + 1));
994     if (!ret)
995 	goto bail2;
996     p = ret;
997     while ((s = FcStrListNext (list)))
998     {
999 	if (p != ret)
1000 	{
1001 	    p[0] = FC_DIR_SEPARATOR;
1002 	    p++;
1003 	}
1004 	len = strlen ((const char *)s);
1005 	memcpy (p, s, len);
1006 	p += len;
1007     }
1008     *p = 0;
1009 
1010 bail2:
1011     FcStrListDone (list);
1012 bail1:
1013     va_end (ap);
1014 bail0:
1015     FcStrSetDestroy (sset);
1016 
1017     return ret;
1018 }
1019 
1020 FcChar8 *
FcStrCopyFilename(const FcChar8 * s)1021 FcStrCopyFilename (const FcChar8 *s)
1022 {
1023     FcChar8 *new;
1024 
1025     if (*s == '~')
1026     {
1027 	FcChar8	*home = FcConfigHome ();
1028 	FcChar8	*full;
1029 	int	size;
1030 	if (!home)
1031 	    return NULL;
1032 	size = strlen ((char *) home) + strlen ((char *) s);
1033 	full = (FcChar8 *) malloc (size + 1);
1034 	if (!full)
1035 	    return NULL;
1036 	strcpy ((char *) full, (char *) home);
1037 	strcat ((char *) full, (char *) s + 1);
1038 	new = FcStrCanonFilename (full);
1039 	free (full);
1040     }
1041     else
1042 	new = FcStrCanonFilename (s);
1043 
1044     return new;
1045 }
1046 
1047 FcChar8 *
FcStrLastSlash(const FcChar8 * path)1048 FcStrLastSlash (const FcChar8  *path)
1049 {
1050     FcChar8	    *slash;
1051 
1052     slash = (FcChar8 *) strrchr ((const char *) path, '/');
1053 #ifdef _WIN32
1054     {
1055         FcChar8     *backslash;
1056 
1057 	backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
1058 	if (!slash || (backslash && backslash > slash))
1059 	    slash = backslash;
1060     }
1061 #endif
1062 
1063     return slash;
1064 }
1065 
1066 FcChar8 *
FcStrDirname(const FcChar8 * file)1067 FcStrDirname (const FcChar8 *file)
1068 {
1069     FcChar8 *slash;
1070     FcChar8 *dir;
1071 
1072     slash = FcStrLastSlash (file);
1073     if (!slash)
1074 	return FcStrCopy ((FcChar8 *) ".");
1075     dir = malloc ((slash - file) + 1);
1076     if (!dir)
1077 	return 0;
1078     strncpy ((char *) dir, (const char *) file, slash - file);
1079     dir[slash - file] = '\0';
1080     return dir;
1081 }
1082 
1083 FcChar8 *
FcStrBasename(const FcChar8 * file)1084 FcStrBasename (const FcChar8 *file)
1085 {
1086     FcChar8 *slash;
1087 
1088     slash = FcStrLastSlash (file);
1089     if (!slash)
1090 	return FcStrCopy (file);
1091     return FcStrCopy (slash + 1);
1092 }
1093 
1094 static FcChar8 *
FcStrCanonAbsoluteFilename(const FcChar8 * s)1095 FcStrCanonAbsoluteFilename (const FcChar8 *s)
1096 {
1097     FcChar8 *file;
1098     FcChar8 *f;
1099     const FcChar8 *slash;
1100     int size;
1101 
1102     size = strlen ((char *) s) + 1;
1103     file = malloc (size);
1104     if (!file)
1105 	return NULL;
1106     slash = NULL;
1107     f = file;
1108 #ifdef _WIN32
1109     if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */
1110 	*f++ = *s++;
1111 #endif
1112     for (;;) {
1113 	if (*s == '/' || *s == '\0')
1114 	{
1115 	    if (slash)
1116 	    {
1117 		switch (s - slash) {
1118 		case 1:
1119 		    f -= 1;	/* squash // and trim final / from file */
1120 		    break;
1121 		case 2:
1122 		    if (!strncmp ((char *) slash, "/.", 2))
1123 		    {
1124 			f -= 2;	/* trim /. from file */
1125 		    }
1126 		    break;
1127 		case 3:
1128 		    if (!strncmp ((char *) slash, "/..", 3))
1129 		    {
1130 			f -= 3;	/* trim /.. from file */
1131 			while (f > file) {
1132 			    if (*--f == '/')
1133 				break;
1134 			}
1135 		    }
1136 		    break;
1137 		}
1138 	    }
1139 	    slash = s;
1140 	}
1141 	if (!(*f++ = *s++))
1142 	    break;
1143     }
1144     return file;
1145 }
1146 
1147 #ifdef _WIN32
1148 /*
1149  * Convert '\\' to '/' , remove double '/'
1150  */
1151 static void
FcConvertDosPath(char * str)1152 FcConvertDosPath (char *str)
1153 {
1154   size_t len = strlen (str);
1155   char *p = str;
1156   char *dest = str;
1157   char *end = str + len;
1158   char last = 0;
1159 
1160   if (*p == '\\')
1161     {
1162       *p = '/';
1163       p++;
1164       dest++;
1165     }
1166   while (p < end)
1167     {
1168       if (*p == '\\')
1169 	*p = '/';
1170 
1171       if (*p != '/'
1172 	  || last != '/')
1173 	{
1174 	  *dest++ = *p;
1175 	}
1176 
1177       last = *p;
1178       p++;
1179     }
1180 
1181   *dest = 0;
1182 }
1183 #endif
1184 
1185 FcChar8 *
FcStrCanonFilename(const FcChar8 * s)1186 FcStrCanonFilename (const FcChar8 *s)
1187 {
1188 #ifdef _WIN32
1189     FcChar8 full[FC_MAX_FILE_LEN + 2];
1190     int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1,
1191 				(LPSTR) full, NULL);
1192 
1193     if (size == 0)
1194 	perror ("GetFullPathName");
1195 
1196     FcConvertDosPath ((char *) full);
1197     return FcStrCanonAbsoluteFilename (full);
1198 #else
1199     if (s[0] == '/')
1200 	return FcStrCanonAbsoluteFilename (s);
1201     else
1202     {
1203 	FcChar8	*full;
1204 	FcChar8 *file;
1205 
1206 	FcChar8	cwd[FC_MAX_FILE_LEN + 2];
1207 	if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL)
1208 	    return NULL;
1209 	full = FcStrBuildFilename (cwd, s, NULL);
1210 	file = FcStrCanonAbsoluteFilename (full);
1211 	FcStrFree (full);
1212 	return file;
1213     }
1214 #endif
1215 }
1216 
1217 
1218 FcStrSet *
FcStrSetCreate(void)1219 FcStrSetCreate (void)
1220 {
1221     return FcStrSetCreateEx (FCSS_DEFAULT);
1222 }
1223 
1224 FcStrSet *
FcStrSetCreateEx(unsigned int control)1225 FcStrSetCreateEx (unsigned int control)
1226 {
1227     FcStrSet	*set = malloc (sizeof (FcStrSet));
1228     if (!set)
1229 	return 0;
1230     FcRefInit (&set->ref, 1);
1231     set->num = 0;
1232     set->size = 0;
1233     set->strs = 0;
1234     set->control = control;
1235     return set;
1236 }
1237 
1238 static FcBool
_FcStrSetGrow(FcStrSet * set,int growElements)1239 _FcStrSetGrow (FcStrSet *set, int growElements)
1240 {
1241     /* accommodate an additional NULL entry at the end of the array */
1242     FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *));
1243     if (!strs)
1244         return FcFalse;
1245     if (set->num)
1246         memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
1247     if (set->strs)
1248         free (set->strs);
1249     set->size = set->size + growElements;
1250     set->strs = strs;
1251     return FcTrue;
1252 }
1253 
1254 static FcBool
_FcStrSetAppend(FcStrSet * set,FcChar8 * s)1255 _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
1256 {
1257     if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES))
1258     {
1259         if (FcStrSetMember (set, s))
1260         {
1261             FcStrFree (s);
1262             return FcTrue;
1263         }
1264     }
1265     if (set->num == set->size)
1266     {
1267         int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1;
1268         if (!_FcStrSetGrow(set, growElements))
1269             return FcFalse;
1270     }
1271     set->strs[set->num++] = s;
1272     set->strs[set->num] = 0;
1273     return FcTrue;
1274 }
1275 
1276 FcBool
FcStrSetMember(FcStrSet * set,const FcChar8 * s)1277 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
1278 {
1279     int	i;
1280 
1281     for (i = 0; i < set->num; i++)
1282 	if (!FcStrCmp (set->strs[i], s))
1283 	    return FcTrue;
1284     return FcFalse;
1285 }
1286 
1287 static int
fc_strcmp_r(const FcChar8 * s1,const FcChar8 * s2,const FcChar8 ** ret)1288 fc_strcmp_r (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 **ret)
1289 {
1290     FcChar8 c1, c2;
1291 
1292     if (s1 == s2)
1293     {
1294 	if (ret)
1295 	    *ret = NULL;
1296 	return 0;
1297     }
1298     for (;;)
1299     {
1300 	if (s1)
1301 	    c1 = *s1++;
1302 	else
1303 	    c1 = 0;
1304 	if (s2)
1305 	    c2 = *s2++;
1306 	else
1307 	    c2 = 0;
1308 	if (!c1 || c1 != c2)
1309 	    break;
1310     }
1311     if (ret)
1312 	*ret = s1;
1313     return (int) c1  - (int) c2;
1314 }
1315 
1316 FcBool
FcStrSetMemberAB(FcStrSet * set,const FcChar8 * a,FcChar8 * b,FcChar8 ** ret)1317 FcStrSetMemberAB (FcStrSet *set, const FcChar8 *a, FcChar8 *b, FcChar8 **ret)
1318 {
1319     int i;
1320     const FcChar8 *s = NULL;
1321 
1322     for (i = 0; i < set->num; i++)
1323     {
1324 	if (!fc_strcmp_r (set->strs[i], a, &s) && s)
1325 	{
1326 	    if (!fc_strcmp_r (s, b, NULL))
1327 	    {
1328 		if (ret)
1329 		    *ret = set->strs[i];
1330 		return FcTrue;
1331 	    }
1332 	}
1333     }
1334     if (ret)
1335 	*ret = NULL;
1336     return FcFalse;
1337 }
1338 
1339 FcBool
FcStrSetEqual(FcStrSet * sa,FcStrSet * sb)1340 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
1341 {
1342     int	i;
1343     if (sa->num != sb->num)
1344 	return FcFalse;
1345     for (i = 0; i < sa->num; i++)
1346 	if (!FcStrSetMember (sb, sa->strs[i]))
1347 	    return FcFalse;
1348     return FcTrue;
1349 }
1350 
1351 FcBool
FcStrSetAdd(FcStrSet * set,const FcChar8 * s)1352 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
1353 {
1354     FcChar8 *new = FcStrCopy (s);
1355     if (!new)
1356 	return FcFalse;
1357     if (!_FcStrSetAppend (set, new))
1358     {
1359 	FcStrFree (new);
1360 	return FcFalse;
1361     }
1362     return FcTrue;
1363 }
1364 
1365 FcBool
FcStrSetAddTriple(FcStrSet * set,const FcChar8 * a,const FcChar8 * b,const FcChar8 * c)1366 FcStrSetAddTriple (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *c)
1367 {
1368     FcChar8 *new = FcStrMakeTriple (a, b, c);
1369     if (!new)
1370 	return FcFalse;
1371     if (!_FcStrSetAppend (set, new))
1372     {
1373 	FcStrFree (new);
1374 	return FcFalse;
1375     }
1376     return FcTrue;
1377 }
1378 
1379 const FcChar8 *
FcStrTripleSecond(FcChar8 * str)1380 FcStrTripleSecond (FcChar8 *str)
1381 {
1382     FcChar8 *second = str + strlen((char *) str) + 1;
1383 
1384     if (*second == '\0')
1385 	return 0;
1386     return second;
1387 }
1388 
1389 const FcChar8 *
FcStrTripleThird(FcChar8 * str)1390 FcStrTripleThird (FcChar8 *str)
1391 {
1392     FcChar8 *second = str + strlen ((char *) str) + 1;
1393     FcChar8 *third = second + strlen ((char *) second) + 1;
1394 
1395     if (*third == '\0')
1396 	return 0;
1397     return third;
1398 }
1399 
1400 FcBool
FcStrSetAddFilename(FcStrSet * set,const FcChar8 * s)1401 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
1402 {
1403     FcChar8 *new = FcStrCopyFilename (s);
1404     if (!new)
1405 	return FcFalse;
1406     if (!_FcStrSetAppend (set, new))
1407     {
1408 	FcStrFree (new);
1409 	return FcFalse;
1410     }
1411     return FcTrue;
1412 }
1413 
1414 FcBool
FcStrSetAddFilenamePairWithSalt(FcStrSet * set,const FcChar8 * a,const FcChar8 * b,const FcChar8 * salt)1415 FcStrSetAddFilenamePairWithSalt (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *salt)
1416 {
1417     FcChar8 *new_a = NULL;
1418     FcChar8 *new_b = NULL;
1419     FcChar8 *rs = NULL;
1420     FcBool  ret;
1421 
1422     if (a)
1423     {
1424 	new_a = FcStrCopyFilename (a);
1425 	if (!new_a)
1426 	    return FcFalse;
1427     }
1428     if (b)
1429     {
1430 	new_b = FcStrCopyFilename(b);
1431 	if (!new_b)
1432 	{
1433 	    if (new_a)
1434 		FcStrFree(new_a);
1435 	    return FcFalse;
1436 	}
1437     }
1438     /* Override maps with new one if exists */
1439     if (FcStrSetMemberAB (set, new_a, new_b, &rs))
1440     {
1441 	FcStrSetDel (set, rs);
1442     }
1443     ret = FcStrSetAddTriple (set, new_a, new_b, salt);
1444     if (new_a)
1445 	FcStrFree (new_a);
1446     if (new_b)
1447 	FcStrFree (new_b);
1448     return ret;
1449 }
1450 
1451 FcBool
FcStrSetAddLangs(FcStrSet * strs,const char * languages)1452 FcStrSetAddLangs (FcStrSet *strs, const char *languages)
1453 {
1454     const char *p = languages, *next;
1455     FcChar8 lang[128] = {0}, *normalized_lang;
1456     size_t len;
1457     FcBool ret = FcFalse;
1458 
1459     if (!languages)
1460 	return FcFalse;
1461 
1462     while ((next = strchr (p, ':')))
1463     {
1464 	len = next - p;
1465 	len = FC_MIN (len, 127);
1466 	strncpy ((char *) lang, p, len);
1467 	lang[len] = 0;
1468 	/* ignore an empty item */
1469 	if (*lang)
1470 	{
1471 	    normalized_lang = FcLangNormalize ((const FcChar8 *) lang);
1472 	    if (normalized_lang)
1473 	    {
1474 		FcStrSetAdd (strs, normalized_lang);
1475 		FcStrFree (normalized_lang);
1476 		ret = FcTrue;
1477 	    }
1478 	}
1479 	p = next + 1;
1480     }
1481     if (*p)
1482     {
1483 	normalized_lang = FcLangNormalize ((const FcChar8 *) p);
1484 	if (normalized_lang)
1485 	{
1486 	    FcStrSetAdd (strs, normalized_lang);
1487 	    FcStrFree (normalized_lang);
1488 	    ret = FcTrue;
1489 	}
1490     }
1491 
1492     return ret;
1493 }
1494 
1495 FcBool
FcStrSetDel(FcStrSet * set,const FcChar8 * s)1496 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
1497 {
1498     int	i;
1499 
1500     for (i = 0; i < set->num; i++)
1501 	if (!FcStrCmp (set->strs[i], s))
1502 	{
1503 	    FcStrFree (set->strs[i]);
1504 	    /*
1505 	     * copy remaining string pointers and trailing
1506 	     * NULL
1507 	     */
1508 	    memmove (&set->strs[i], &set->strs[i+1],
1509 		     (set->num - i) * sizeof (FcChar8 *));
1510 	    set->num--;
1511 	    return FcTrue;
1512 	}
1513     return FcFalse;
1514 }
1515 
1516 FcBool
FcStrSetDeleteAll(FcStrSet * set)1517 FcStrSetDeleteAll (FcStrSet *set)
1518 {
1519     int i;
1520 
1521     if (FcRefIsConst (&set->ref))
1522 	return FcFalse;
1523 
1524     for (i = set->num; i > 0; i--)
1525     {
1526 	FcStrFree (set->strs[i - 1]);
1527 	set->num--;
1528     }
1529     return FcTrue;
1530 }
1531 
1532 /* TODO Make public */
1533 static FcStrSet *
FcStrSetReference(FcStrSet * set)1534 FcStrSetReference (FcStrSet *set)
1535 {
1536     if (FcRefIsConst (&set->ref))
1537 	return set;
1538 
1539     FcRefInc (&set->ref);
1540     return set;
1541 }
1542 
1543 void
FcStrSetDestroy(FcStrSet * set)1544 FcStrSetDestroy (FcStrSet *set)
1545 {
1546     int	i;
1547 
1548     /* We rely on this in FcGetDefaultLangs for caching. */
1549     if (FcRefIsConst (&set->ref))
1550 	return;
1551 
1552     if (FcRefDec (&set->ref) != 1)
1553 	return;
1554 
1555     for (i = 0; i < set->num; i++)
1556 	FcStrFree (set->strs[i]);
1557     if (set->strs)
1558 	free (set->strs);
1559     free (set);
1560 }
1561 
1562 FcStrList *
FcStrListCreate(FcStrSet * set)1563 FcStrListCreate (FcStrSet *set)
1564 {
1565     FcStrList	*list;
1566 
1567     list = malloc (sizeof (FcStrList));
1568     if (!list)
1569 	return 0;
1570     list->set = set;
1571     FcStrSetReference (set);
1572     list->n = 0;
1573     return list;
1574 }
1575 
1576 void
FcStrListFirst(FcStrList * list)1577 FcStrListFirst (FcStrList *list)
1578 {
1579     list->n = 0;
1580 }
1581 
1582 FcChar8 *
FcStrListNext(FcStrList * list)1583 FcStrListNext (FcStrList *list)
1584 {
1585     if (list->n >= list->set->num)
1586 	return 0;
1587     return list->set->strs[list->n++];
1588 }
1589 
1590 void
FcStrListDone(FcStrList * list)1591 FcStrListDone (FcStrList *list)
1592 {
1593     FcStrSetDestroy (list->set);
1594     free (list);
1595 }
1596 
1597 #define __fcstr__
1598 #include "fcaliastail.h"
1599 #undef __fcstr__
1600