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