Coverage Report

Created: 2025-07-07 10:01

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