Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/fontconfig/src/fcxml.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * fontconfig/src/fcxml.c
3
 *
4
 * Copyright © 2002 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 <fcntl.h>
28
#include <stdarg.h>
29
#include <string.h>
30
31
#ifdef HAVE_DIRENT_H
32
#  include <dirent.h>
33
#endif
34
35
#ifdef ENABLE_LIBXML2
36
37
#  include <libxml/parser.h>
38
39
#  define XML_Char                 xmlChar
40
#  define XML_Parser               xmlParserCtxtPtr
41
#  define XML_ParserFree           xmlFreeParserCtxt
42
#  define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
43
#  define XML_GetErrorCode         xmlCtxtGetLastError
44
#  define XML_ErrorString(Error)   (Error)->message
45
46
#else /* ENABLE_LIBXML2 */
47
48
#  ifndef HAVE_XMLPARSE_H
49
#    define HAVE_XMLPARSE_H 0
50
#  endif
51
52
#  if HAVE_XMLPARSE_H
53
#    include <xmlparse.h>
54
#  else
55
#    include <expat.h>
56
#  endif
57
58
#endif /* ENABLE_LIBXML2 */
59
60
#ifdef _WIN32
61
#  include <mbstring.h>
62
extern FcChar8               fontconfig_instprefix[];
63
pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
64
pfnSHGetFolderPathA          pSHGetFolderPathA = NULL;
65
static void
66
_ensureWin32GettersReady ();
67
#endif
68
69
static void
70
FcExprDestroy (FcExpr *e);
71
static FcBool
72
_FcConfigParse (FcConfig      *config,
73
                const FcChar8 *name,
74
                FcBool         complain,
75
                FcBool         load);
76
77
void
78
FcTestDestroy (FcTest *test)
79
0
{
80
0
    FcExprDestroy (test->expr);
81
0
    free (test);
82
0
}
83
84
void
85
FcRuleDestroy (FcRule *rule)
86
0
{
87
0
    FcRule *n = rule->next;
88
89
0
    switch (rule->type) {
90
0
    case FcRuleTest:
91
0
  FcTestDestroy (rule->u.test);
92
0
  break;
93
0
    case FcRuleEdit:
94
0
  FcEditDestroy (rule->u.edit);
95
0
  break;
96
0
    case FcRuleUnknown:
97
0
    default:
98
0
  break;
99
0
    }
100
0
    free (rule);
101
0
    if (n)
102
0
  FcRuleDestroy (n);
103
0
}
104
105
static FcExpr *
106
FcExprCreateInteger (FcConfig *config, int i)
107
0
{
108
0
    FcExpr *e = FcConfigAllocExpr (config);
109
0
    if (e) {
110
0
  e->op = FcOpInteger;
111
0
  e->u.ival = i;
112
0
    }
113
0
    return e;
114
0
}
115
116
static FcExpr *
117
FcExprCreateDouble (FcConfig *config, double d)
118
0
{
119
0
    FcExpr *e = FcConfigAllocExpr (config);
120
0
    if (e) {
121
0
  e->op = FcOpDouble;
122
0
  e->u.dval = d;
123
0
    }
124
0
    return e;
125
0
}
126
127
static FcExpr *
128
FcExprCreateString (FcConfig *config, const FcChar8 *s)
129
0
{
130
0
    FcExpr *e = FcConfigAllocExpr (config);
131
0
    if (e) {
132
0
  e->op = FcOpString;
133
0
  e->u.sval = FcStrdup (s);
134
0
    }
135
0
    return e;
136
0
}
137
138
static FcExprMatrix *
139
FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
140
0
{
141
0
    FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
142
0
    if (m) {
143
0
  *m = *matrix;
144
0
    }
145
0
    return m;
146
0
}
147
148
static void
149
FcExprMatrixFreeShallow (FcExprMatrix *m)
150
0
{
151
0
    if (!m)
152
0
  return;
153
154
0
    free (m);
155
0
}
156
157
static void
158
FcExprMatrixFree (FcExprMatrix *m)
159
0
{
160
0
    if (!m)
161
0
  return;
162
163
0
    FcExprDestroy (m->xx);
164
0
    FcExprDestroy (m->xy);
165
0
    FcExprDestroy (m->yx);
166
0
    FcExprDestroy (m->yy);
167
168
0
    free (m);
169
0
}
170
171
static FcExpr *
172
FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
173
0
{
174
0
    FcExpr *e = FcConfigAllocExpr (config);
175
0
    if (e) {
176
0
  e->op = FcOpMatrix;
177
0
  e->u.mexpr = FcExprMatrixCopyShallow (matrix);
178
0
    }
179
0
    return e;
180
0
}
181
182
static FcExpr *
183
FcExprCreateRange (FcConfig *config, FcRange *range)
184
0
{
185
0
    FcExpr *e = FcConfigAllocExpr (config);
186
0
    if (e) {
187
0
  e->op = FcOpRange;
188
0
  e->u.rval = FcRangeCopy (range);
189
0
    }
190
0
    return e;
191
0
}
192
193
static FcExpr *
194
FcExprCreateBool (FcConfig *config, FcBool b)
195
0
{
196
0
    FcExpr *e = FcConfigAllocExpr (config);
197
0
    if (e) {
198
0
  e->op = FcOpBool;
199
0
  e->u.bval = b;
200
0
    }
201
0
    return e;
202
0
}
203
204
static FcExpr *
205
FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
206
0
{
207
0
    FcExpr *e = FcConfigAllocExpr (config);
208
0
    if (e) {
209
0
  e->op = FcOpCharSet;
210
0
  e->u.cval = FcCharSetCopy (charset);
211
0
    }
212
0
    return e;
213
0
}
214
215
static FcExpr *
216
FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
217
0
{
218
0
    FcExpr *e = FcConfigAllocExpr (config);
219
0
    if (e) {
220
0
  e->op = FcOpLangSet;
221
0
  e->u.lval = FcLangSetCopy (langset);
222
0
    }
223
0
    return e;
224
0
}
225
226
static FcExpr *
227
FcExprCreateName (FcConfig *config, FcExprName name)
228
0
{
229
0
    FcExpr *e = FcConfigAllocExpr (config);
230
0
    if (e) {
231
0
  e->op = FcOpField;
232
0
  e->u.name = name;
233
0
    }
234
0
    return e;
235
0
}
236
237
static FcExpr *
238
FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
239
0
{
240
0
    FcExpr *e = FcConfigAllocExpr (config);
241
0
    if (e) {
242
0
  e->op = FcOpConst;
243
0
  e->u.constant = FcStrdup (constant);
244
0
    }
245
0
    return e;
246
0
}
247
248
static FcExpr *
249
FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
250
0
{
251
0
    FcExpr *e = FcConfigAllocExpr (config);
252
0
    if (e) {
253
0
  e->op = op;
254
0
  e->u.tree.left = left;
255
0
  e->u.tree.right = right;
256
0
    }
257
0
    return e;
258
0
}
259
260
static void
261
FcExprDestroy (FcExpr *e)
262
0
{
263
0
    if (!e)
264
0
  return;
265
0
    switch (FC_OP_GET_OP (e->op)) {
266
0
    case FcOpInteger:
267
0
  break;
268
0
    case FcOpDouble:
269
0
  break;
270
0
    case FcOpString:
271
0
  FcFree (e->u.sval);
272
0
  break;
273
0
    case FcOpMatrix:
274
0
  FcExprMatrixFree (e->u.mexpr);
275
0
  break;
276
0
    case FcOpRange:
277
0
  FcRangeDestroy (e->u.rval);
278
0
  break;
279
0
    case FcOpCharSet:
280
0
  FcCharSetDestroy (e->u.cval);
281
0
  break;
282
0
    case FcOpLangSet:
283
0
  FcLangSetDestroy (e->u.lval);
284
0
  break;
285
0
    case FcOpBool:
286
0
  break;
287
0
    case FcOpField:
288
0
  break;
289
0
    case FcOpConst:
290
0
  FcFree (e->u.constant);
291
0
  break;
292
0
    case FcOpAssign:
293
0
    case FcOpAssignReplace:
294
0
    case FcOpPrepend:
295
0
    case FcOpPrependFirst:
296
0
    case FcOpAppend:
297
0
    case FcOpAppendLast:
298
0
    case FcOpDelete:
299
0
    case FcOpDeleteAll:
300
0
  break;
301
0
    case FcOpOr:
302
0
    case FcOpAnd:
303
0
    case FcOpEqual:
304
0
    case FcOpNotEqual:
305
0
    case FcOpLess:
306
0
    case FcOpLessEqual:
307
0
    case FcOpMore:
308
0
    case FcOpMoreEqual:
309
0
    case FcOpContains:
310
0
    case FcOpListing:
311
0
    case FcOpNotContains:
312
0
    case FcOpPlus:
313
0
    case FcOpMinus:
314
0
    case FcOpTimes:
315
0
    case FcOpDivide:
316
0
    case FcOpQuest:
317
0
    case FcOpComma:
318
0
  FcExprDestroy (e->u.tree.right);
319
  /* fall through */
320
0
    case FcOpNot:
321
0
    case FcOpFloor:
322
0
    case FcOpCeil:
323
0
    case FcOpRound:
324
0
    case FcOpTrunc:
325
0
  FcExprDestroy (e->u.tree.left);
326
0
  break;
327
0
    case FcOpNil:
328
0
    case FcOpInvalid:
329
0
  break;
330
0
    }
331
332
0
    e->op = FcOpNil;
333
0
}
334
335
void
336
FcEditDestroy (FcEdit *e)
337
0
{
338
0
    if (e->expr)
339
0
  FcExprDestroy (e->expr);
340
0
    free (e);
341
0
}
342
343
typedef enum _FcElement {
344
    FcElementNone,
345
    FcElementFontconfig,
346
    FcElementDir,
347
    FcElementCacheDir,
348
    FcElementCache,
349
    FcElementInclude,
350
    FcElementConfig,
351
    FcElementMatch,
352
    FcElementAlias,
353
    FcElementDescription,
354
    FcElementRemapDir,
355
    FcElementResetDirs,
356
357
    FcElementRescan,
358
359
    FcElementPrefer,
360
    FcElementAccept,
361
    FcElementDefault,
362
    FcElementFamily,
363
364
    FcElementSelectfont,
365
    FcElementAcceptfont,
366
    FcElementRejectfont,
367
    FcElementGlob,
368
    FcElementPattern,
369
    FcElementPatelt,
370
371
    FcElementTest,
372
    FcElementEdit,
373
    FcElementInt,
374
    FcElementDouble,
375
    FcElementString,
376
    FcElementMatrix,
377
    FcElementRange,
378
    FcElementBool,
379
    FcElementCharSet,
380
    FcElementLangSet,
381
    FcElementName,
382
    FcElementConst,
383
    FcElementOr,
384
    FcElementAnd,
385
    FcElementEq,
386
    FcElementNotEq,
387
    FcElementLess,
388
    FcElementLessEq,
389
    FcElementMore,
390
    FcElementMoreEq,
391
    FcElementContains,
392
    FcElementNotContains,
393
    FcElementPlus,
394
    FcElementMinus,
395
    FcElementTimes,
396
    FcElementDivide,
397
    FcElementNot,
398
    FcElementIf,
399
    FcElementFloor,
400
    FcElementCeil,
401
    FcElementRound,
402
    FcElementTrunc,
403
    FcElementUnknown
404
} FcElement;
405
406
static const struct {
407
    const char name[16];
408
    FcElement  element;
409
} fcElementMap[] = {
410
    { "fontconfig",   FcElementFontconfig  },
411
    { "dir",          FcElementDir         },
412
    { "cachedir",     FcElementCacheDir    },
413
    { "cache",        FcElementCache       },
414
    { "include",      FcElementInclude     },
415
    { "config",       FcElementConfig      },
416
    { "match",        FcElementMatch       },
417
    { "alias",        FcElementAlias       },
418
    { "description",  FcElementDescription },
419
    { "remap-dir",    FcElementRemapDir    },
420
    { "reset-dirs",   FcElementResetDirs   },
421
422
    { "rescan",       FcElementRescan      },
423
424
    { "prefer",       FcElementPrefer      },
425
    { "accept",       FcElementAccept      },
426
    { "default",      FcElementDefault     },
427
    { "family",       FcElementFamily      },
428
429
    { "selectfont",   FcElementSelectfont  },
430
    { "acceptfont",   FcElementAcceptfont  },
431
    { "rejectfont",   FcElementRejectfont  },
432
    { "glob",         FcElementGlob        },
433
    { "pattern",      FcElementPattern     },
434
    { "patelt",       FcElementPatelt      },
435
436
    { "test",         FcElementTest        },
437
    { "edit",         FcElementEdit        },
438
    { "int",          FcElementInt         },
439
    { "double",       FcElementDouble      },
440
    { "string",       FcElementString      },
441
    { "matrix",       FcElementMatrix      },
442
    { "range",        FcElementRange       },
443
    { "bool",         FcElementBool        },
444
    { "charset",      FcElementCharSet     },
445
    { "langset",      FcElementLangSet     },
446
    { "name",         FcElementName        },
447
    { "const",        FcElementConst       },
448
    { "or",           FcElementOr          },
449
    { "and",          FcElementAnd         },
450
    { "eq",           FcElementEq          },
451
    { "not_eq",       FcElementNotEq       },
452
    { "less",         FcElementLess        },
453
    { "less_eq",      FcElementLessEq      },
454
    { "more",         FcElementMore        },
455
    { "more_eq",      FcElementMoreEq      },
456
    { "contains",     FcElementContains    },
457
    { "not_contains", FcElementNotContains },
458
    { "plus",         FcElementPlus        },
459
    { "minus",        FcElementMinus       },
460
    { "times",        FcElementTimes       },
461
    { "divide",       FcElementDivide      },
462
    { "not",          FcElementNot         },
463
    { "if",           FcElementIf          },
464
    { "floor",        FcElementFloor       },
465
    { "ceil",         FcElementCeil        },
466
    { "round",        FcElementRound       },
467
    { "trunc",        FcElementTrunc       },
468
};
469
636
#define NUM_ELEMENT_MAPS (int)(sizeof fcElementMap / sizeof fcElementMap[0])
470
471
static const char *fcElementIgnoreName[16] = {
472
    "its:",
473
    NULL
474
};
475
476
static FcElement
477
FcElementMap (const XML_Char *name)
478
318
{
479
318
    int i;
480
636
    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
481
636
  if (!strcmp ((char *)name, fcElementMap[i].name))
482
318
      return fcElementMap[i].element;
483
0
    for (i = 0; fcElementIgnoreName[i] != NULL; i++)
484
0
  if (!strncmp ((char *)name, fcElementIgnoreName[i], strlen (fcElementIgnoreName[i])))
485
0
      return FcElementNone;
486
0
    return FcElementUnknown;
487
0
}
488
489
static const char *
490
FcElementReverseMap (FcElement e)
491
0
{
492
0
    int i;
493
494
0
    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
495
0
  if (fcElementMap[i].element == e)
496
0
      return fcElementMap[i].name;
497
498
0
    return NULL;
499
0
}
500
501
typedef struct _FcPStack {
502
    struct _FcPStack *prev;
503
    FcElement         element;
504
    FcChar8         **attr;
505
    FcStrBuf          str;
506
    FcChar8          *attr_buf_static[16];
507
} FcPStack;
508
509
typedef enum _FcVStackTag {
510
    FcVStackNone,
511
512
    FcVStackString,
513
    FcVStackFamily,
514
    FcVStackConstant,
515
    FcVStackGlob,
516
    FcVStackName,
517
    FcVStackPattern,
518
519
    FcVStackPrefer,
520
    FcVStackAccept,
521
    FcVStackDefault,
522
523
    FcVStackInteger,
524
    FcVStackDouble,
525
    FcVStackMatrix,
526
    FcVStackRange,
527
    FcVStackBool,
528
    FcVStackCharSet,
529
    FcVStackLangSet,
530
531
    FcVStackTest,
532
    FcVStackExpr,
533
    FcVStackEdit
534
} FcVStackTag;
535
536
typedef struct _FcVStack {
537
    struct _FcVStack *prev;
538
    FcPStack         *pstack; /* related parse element */
539
    FcVStackTag       tag;
540
    union {
541
  FcChar8 *string;
542
543
  int           integer;
544
  double        _double;
545
  FcExprMatrix *matrix;
546
  FcRange      *range;
547
  FcBool        bool_;
548
  FcCharSet    *charset;
549
  FcLangSet    *langset;
550
  FcExprName    name;
551
552
  FcTest *test;
553
  FcQual  qual;
554
  FcOp    op;
555
  FcExpr *expr;
556
  FcEdit *edit;
557
558
  FcPattern *pattern;
559
    } u;
560
} FcVStack;
561
562
typedef struct _FcConfigParse {
563
    FcPStack      *pstack;
564
    FcVStack      *vstack;
565
    FcBool         error;
566
    const FcChar8 *name;
567
    FcConfig      *config;
568
    FcRuleSet     *ruleset;
569
    XML_Parser     parser;
570
    unsigned int   pstack_static_used;
571
    FcPStack       pstack_static[8];
572
    unsigned int   vstack_static_used;
573
    FcVStack       vstack_static[64];
574
    FcBool         scanOnly;
575
} FcConfigParse;
576
577
typedef enum _FcConfigSeverity {
578
    FcSevereInfo,
579
    FcSevereWarning,
580
    FcSevereError
581
} FcConfigSeverity;
582
583
static void
584
FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
585
0
{
586
0
    const char *s = "unknown";
587
0
    va_list     args;
588
589
0
    va_start (args, fmt);
590
591
0
    switch (severe) {
592
0
    case FcSevereInfo: s = "info"; break;
593
0
    case FcSevereWarning: s = "warning"; break;
594
0
    case FcSevereError: s = "error"; break;
595
0
    }
596
0
    if (parse) {
597
0
  if (parse->name)
598
0
      fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
599
0
               parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
600
0
  else
601
0
      fprintf (stderr, "Fontconfig %s: line %d: ", s,
602
0
               (int)XML_GetCurrentLineNumber (parse->parser));
603
0
  if (severe >= FcSevereError)
604
0
      parse->error = FcTrue;
605
0
    } else
606
0
  fprintf (stderr, "Fontconfig %s: ", s);
607
0
    vfprintf (stderr, fmt, args);
608
0
    fprintf (stderr, "\n");
609
0
    va_end (args);
610
0
}
611
612
static FcExpr *
613
FcPopExpr (FcConfigParse *parse);
614
615
static const char *
616
FcTypeName (FcType type)
617
0
{
618
0
    switch (type) {
619
0
    case FcTypeVoid:
620
0
  return "void";
621
0
    case FcTypeInteger:
622
0
    case FcTypeDouble:
623
0
  return "number";
624
0
    case FcTypeString:
625
0
  return "string";
626
0
    case FcTypeBool:
627
0
  return "bool";
628
0
    case FcTypeMatrix:
629
0
  return "matrix";
630
0
    case FcTypeCharSet:
631
0
  return "charset";
632
0
    case FcTypeFTFace:
633
0
  return "FT_Face";
634
0
    case FcTypeLangSet:
635
0
  return "langset";
636
0
    case FcTypeRange:
637
0
  return "range";
638
0
    case FcTypeUnknown:
639
0
    default:
640
0
  return "unknown";
641
0
    }
642
0
}
643
644
static void
645
FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
646
0
{
647
0
    if (value == FcTypeInteger)
648
0
  value = FcTypeDouble;
649
0
    if (type == FcTypeInteger)
650
0
  type = FcTypeDouble;
651
0
    if (value != type) {
652
0
  if ((value == FcTypeLangSet && type == FcTypeString) ||
653
0
      (value == FcTypeString && type == FcTypeLangSet) ||
654
0
      (value == FcTypeDouble && type == FcTypeRange))
655
0
      return;
656
0
  if (type == FcTypeUnknown)
657
0
      return;
658
  /* It's perfectly fine to use user-define elements in expressions,
659
   * so don't warn in that case. */
660
0
  if (value == FcTypeUnknown)
661
0
      return;
662
0
  FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
663
0
                   FcTypeName (value), FcTypeName (type));
664
0
    }
665
0
}
666
667
static void
668
FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
669
0
{
670
0
    const FcObjectType *o;
671
0
    const FcConstant   *c;
672
673
    /* If parsing the expression failed, some nodes may be NULL */
674
0
    if (!expr)
675
0
  return;
676
677
0
    switch (FC_OP_GET_OP (expr->op)) {
678
0
    case FcOpInteger:
679
0
    case FcOpDouble:
680
0
  FcTypecheckValue (parse, FcTypeDouble, type);
681
0
  break;
682
0
    case FcOpString:
683
0
  FcTypecheckValue (parse, FcTypeString, type);
684
0
  break;
685
0
    case FcOpMatrix:
686
0
  FcTypecheckValue (parse, FcTypeMatrix, type);
687
0
  break;
688
0
    case FcOpBool:
689
0
  FcTypecheckValue (parse, FcTypeBool, type);
690
0
  break;
691
0
    case FcOpCharSet:
692
0
  FcTypecheckValue (parse, FcTypeCharSet, type);
693
0
  break;
694
0
    case FcOpLangSet:
695
0
  FcTypecheckValue (parse, FcTypeLangSet, type);
696
0
  break;
697
0
    case FcOpRange:
698
0
  FcTypecheckValue (parse, FcTypeRange, type);
699
0
  break;
700
0
    case FcOpNil:
701
0
  break;
702
0
    case FcOpField:
703
0
  o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
704
0
  if (o)
705
0
      FcTypecheckValue (parse, o->type, type);
706
0
  break;
707
0
    case FcOpConst:
708
0
  c = FcNameGetConstant (expr->u.constant);
709
0
  if (c) {
710
0
      o = FcNameGetObjectType (c->object);
711
0
      if (o)
712
0
    FcTypecheckValue (parse, o->type, type);
713
0
  } else
714
0
      FcConfigMessage (parse, FcSevereWarning,
715
0
                       "invalid constant used : %s",
716
0
                       expr->u.constant);
717
0
  break;
718
0
    case FcOpQuest:
719
0
  FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
720
0
  FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
721
0
  FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
722
0
  break;
723
0
    case FcOpAssign:
724
0
    case FcOpAssignReplace:
725
0
  break;
726
0
    case FcOpEqual:
727
0
    case FcOpNotEqual:
728
0
    case FcOpLess:
729
0
    case FcOpLessEqual:
730
0
    case FcOpMore:
731
0
    case FcOpMoreEqual:
732
0
    case FcOpContains:
733
0
    case FcOpNotContains:
734
0
    case FcOpListing:
735
0
  FcTypecheckValue (parse, FcTypeBool, type);
736
0
  break;
737
0
    case FcOpComma:
738
0
    case FcOpOr:
739
0
    case FcOpAnd:
740
0
    case FcOpPlus:
741
0
    case FcOpMinus:
742
0
    case FcOpTimes:
743
0
    case FcOpDivide:
744
0
  FcTypecheckExpr (parse, expr->u.tree.left, type);
745
0
  FcTypecheckExpr (parse, expr->u.tree.right, type);
746
0
  break;
747
0
    case FcOpNot:
748
0
  FcTypecheckValue (parse, FcTypeBool, type);
749
0
  FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
750
0
  break;
751
0
    case FcOpFloor:
752
0
    case FcOpCeil:
753
0
    case FcOpRound:
754
0
    case FcOpTrunc:
755
0
  FcTypecheckValue (parse, FcTypeDouble, type);
756
0
  FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
757
0
  break;
758
0
    default:
759
0
  break;
760
0
    }
761
0
}
762
763
static FcTest *
764
FcTestCreate (FcConfigParse *parse,
765
              FcMatchKind    kind,
766
              FcQual         qual,
767
              const FcChar8 *field,
768
              unsigned int   compare,
769
              FcExpr        *expr)
770
0
{
771
0
    FcTest *test = (FcTest *)malloc (sizeof (FcTest));
772
773
0
    if (test) {
774
0
  const FcObjectType *o;
775
776
0
  test->kind = kind;
777
0
  test->qual = qual;
778
0
  test->object = FcObjectFromName ((const char *)field);
779
0
  test->op = compare;
780
0
  test->expr = expr;
781
0
  o = FcNameGetObjectType (FcObjectName (test->object));
782
0
  if (o)
783
0
      FcTypecheckExpr (parse, expr, o->type);
784
0
    }
785
0
    return test;
786
0
}
787
788
static FcEdit *
789
FcEditCreate (FcConfigParse *parse,
790
              FcObject       object,
791
              FcOp           op,
792
              FcExpr        *expr,
793
              FcValueBinding binding)
794
0
{
795
0
    FcEdit *e = (FcEdit *)malloc (sizeof (FcEdit));
796
797
0
    if (e) {
798
0
  const FcObjectType *o;
799
800
0
  e->object = object;
801
0
  e->op = op;
802
0
  e->expr = expr;
803
0
  e->binding = binding;
804
0
  o = FcNameGetObjectType (FcObjectName (e->object));
805
0
  if (o)
806
0
      FcTypecheckExpr (parse, expr, o->type);
807
0
    }
808
0
    return e;
809
0
}
810
811
static FcRule *
812
FcRuleCreate (FcRuleType type,
813
              void      *p)
814
0
{
815
0
    FcRule *r = (FcRule *)malloc (sizeof (FcRule));
816
817
0
    if (!r)
818
0
  return NULL;
819
820
0
    r->next = NULL;
821
0
    r->type = type;
822
0
    switch (type) {
823
0
    case FcRuleTest:
824
0
  r->u.test = (FcTest *)p;
825
0
  break;
826
0
    case FcRuleEdit:
827
0
  r->u.edit = (FcEdit *)p;
828
0
  break;
829
0
    case FcRuleUnknown:
830
0
    default:
831
0
  free (r);
832
0
  r = NULL;
833
0
  break;
834
0
    }
835
836
0
    return r;
837
0
}
838
839
static FcVStack *
840
FcVStackCreateAndPush (FcConfigParse *parse)
841
0
{
842
0
    FcVStack *newp;
843
844
0
    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
845
0
  newp = &parse->vstack_static[parse->vstack_static_used++];
846
0
    else {
847
0
  newp = malloc (sizeof (FcVStack));
848
0
  if (!newp)
849
0
      return 0;
850
0
    }
851
0
    newp->tag = FcVStackNone;
852
0
    newp->prev = 0;
853
854
0
    newp->prev = parse->vstack;
855
0
    newp->pstack = parse->pstack ? parse->pstack->prev : 0;
856
0
    parse->vstack = newp;
857
858
0
    return newp;
859
0
}
860
861
static FcBool
862
FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
863
0
{
864
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
865
0
    if (!vstack)
866
0
  return FcFalse;
867
0
    vstack->u.string = string;
868
0
    vstack->tag = tag;
869
0
    return FcTrue;
870
0
}
871
872
static FcBool
873
FcVStackPushInteger (FcConfigParse *parse, int integer)
874
0
{
875
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
876
0
    if (!vstack)
877
0
  return FcFalse;
878
0
    vstack->u.integer = integer;
879
0
    vstack->tag = FcVStackInteger;
880
0
    return FcTrue;
881
0
}
882
883
static FcBool
884
FcVStackPushDouble (FcConfigParse *parse, double _double)
885
0
{
886
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
887
0
    if (!vstack)
888
0
  return FcFalse;
889
0
    vstack->u._double = _double;
890
0
    vstack->tag = FcVStackDouble;
891
0
    return FcTrue;
892
0
}
893
894
static FcBool
895
FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
896
0
{
897
0
    FcVStack *vstack;
898
0
    vstack = FcVStackCreateAndPush (parse);
899
0
    if (!vstack)
900
0
  return FcFalse;
901
0
    vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
902
0
    vstack->tag = FcVStackMatrix;
903
0
    return FcTrue;
904
0
}
905
906
static FcBool
907
FcVStackPushRange (FcConfigParse *parse, FcRange *range)
908
0
{
909
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
910
0
    if (!vstack)
911
0
  return FcFalse;
912
0
    vstack->u.range = range;
913
0
    vstack->tag = FcVStackRange;
914
0
    return FcTrue;
915
0
}
916
917
static FcBool
918
FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
919
0
{
920
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
921
0
    if (!vstack)
922
0
  return FcFalse;
923
0
    vstack->u.bool_ = bool_;
924
0
    vstack->tag = FcVStackBool;
925
0
    return FcTrue;
926
0
}
927
928
static FcBool
929
FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
930
0
{
931
0
    FcVStack *vstack;
932
0
    if (!charset)
933
0
  return FcFalse;
934
0
    vstack = FcVStackCreateAndPush (parse);
935
0
    if (!vstack)
936
0
  return FcFalse;
937
0
    vstack->u.charset = charset;
938
0
    vstack->tag = FcVStackCharSet;
939
0
    return FcTrue;
940
0
}
941
942
static FcBool
943
FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
944
0
{
945
0
    FcVStack *vstack;
946
0
    if (!langset)
947
0
  return FcFalse;
948
0
    vstack = FcVStackCreateAndPush (parse);
949
0
    if (!vstack)
950
0
  return FcFalse;
951
0
    vstack->u.langset = langset;
952
0
    vstack->tag = FcVStackLangSet;
953
0
    return FcTrue;
954
0
}
955
956
static FcBool
957
FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
958
0
{
959
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
960
0
    if (!vstack)
961
0
  return FcFalse;
962
0
    vstack->u.name.object = object;
963
0
    vstack->u.name.kind = kind;
964
0
    vstack->tag = FcVStackName;
965
0
    return FcTrue;
966
0
}
967
968
static FcBool
969
FcVStackPushTest (FcConfigParse *parse, FcTest *test)
970
0
{
971
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
972
0
    if (!vstack)
973
0
  return FcFalse;
974
0
    vstack->u.test = test;
975
0
    vstack->tag = FcVStackTest;
976
0
    return FcTrue;
977
0
}
978
979
static FcBool
980
FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
981
0
{
982
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
983
0
    if (!vstack)
984
0
  return FcFalse;
985
0
    vstack->u.expr = expr;
986
0
    vstack->tag = tag;
987
0
    return FcTrue;
988
0
}
989
990
static FcBool
991
FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
992
0
{
993
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
994
0
    if (!vstack)
995
0
  return FcFalse;
996
0
    vstack->u.edit = edit;
997
0
    vstack->tag = FcVStackEdit;
998
0
    return FcTrue;
999
0
}
1000
1001
static FcBool
1002
FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
1003
0
{
1004
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1005
0
    if (!vstack)
1006
0
  return FcFalse;
1007
0
    vstack->u.pattern = pattern;
1008
0
    vstack->tag = FcVStackPattern;
1009
0
    return FcTrue;
1010
0
}
1011
1012
static FcVStack *
1013
FcVStackFetch (FcConfigParse *parse, int off)
1014
0
{
1015
0
    FcVStack *vstack;
1016
1017
0
    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev)
1018
0
  ;
1019
0
    return vstack;
1020
0
}
1021
1022
static FcVStack *
1023
FcVStackPeek (FcConfigParse *parse)
1024
318
{
1025
318
    FcVStack *vstack = parse->vstack;
1026
1027
318
    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
1028
318
}
1029
1030
static void
1031
FcVStackPopAndDestroy (FcConfigParse *parse)
1032
0
{
1033
0
    FcVStack *vstack = parse->vstack;
1034
1035
0
    if (!vstack || vstack->pstack != parse->pstack)
1036
0
  return;
1037
1038
0
    parse->vstack = vstack->prev;
1039
1040
0
    switch (vstack->tag) {
1041
0
    case FcVStackNone:
1042
0
  break;
1043
0
    case FcVStackName:
1044
0
  break;
1045
0
    case FcVStackFamily:
1046
0
  break;
1047
0
    case FcVStackString:
1048
0
    case FcVStackConstant:
1049
0
    case FcVStackGlob:
1050
0
  FcStrFree (vstack->u.string);
1051
0
  break;
1052
0
    case FcVStackPattern:
1053
0
  FcPatternDestroy (vstack->u.pattern);
1054
0
  break;
1055
0
    case FcVStackInteger:
1056
0
    case FcVStackDouble:
1057
0
  break;
1058
0
    case FcVStackMatrix:
1059
0
  FcExprMatrixFreeShallow (vstack->u.matrix);
1060
0
  break;
1061
0
    case FcVStackBool:
1062
0
  break;
1063
0
    case FcVStackRange:
1064
0
  FcRangeDestroy (vstack->u.range);
1065
0
  break;
1066
0
    case FcVStackCharSet:
1067
0
  FcCharSetDestroy (vstack->u.charset);
1068
0
  break;
1069
0
    case FcVStackLangSet:
1070
0
  FcLangSetDestroy (vstack->u.langset);
1071
0
  break;
1072
0
    case FcVStackTest:
1073
0
  FcTestDestroy (vstack->u.test);
1074
0
  break;
1075
0
    case FcVStackExpr:
1076
0
    case FcVStackPrefer:
1077
0
    case FcVStackAccept:
1078
0
    case FcVStackDefault:
1079
0
  FcExprDestroy (vstack->u.expr);
1080
0
  break;
1081
0
    case FcVStackEdit:
1082
0
  FcEditDestroy (vstack->u.edit);
1083
0
  break;
1084
0
    }
1085
1086
0
    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1087
0
  parse->vstack_static_used--;
1088
0
    else
1089
0
  free (vstack);
1090
0
}
1091
1092
static void
1093
FcVStackClear (FcConfigParse *parse)
1094
318
{
1095
318
    while (FcVStackPeek (parse))
1096
0
  FcVStackPopAndDestroy (parse);
1097
318
}
1098
1099
static int
1100
FcVStackElements (FcConfigParse *parse)
1101
0
{
1102
0
    int       h = 0;
1103
0
    FcVStack *vstack = parse->vstack;
1104
0
    while (vstack && vstack->pstack == parse->pstack) {
1105
0
  h++;
1106
0
  vstack = vstack->prev;
1107
0
    }
1108
0
    return h;
1109
0
}
1110
1111
static FcChar8 **
1112
FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1113
318
{
1114
318
    int       slen;
1115
318
    int       i;
1116
318
    FcChar8 **newp;
1117
318
    FcChar8  *s;
1118
1119
318
    if (!attr)
1120
0
  return 0;
1121
318
    slen = 0;
1122
318
    for (i = 0; attr[i]; i++)
1123
0
  slen += strlen ((char *)attr[i]) + 1;
1124
318
    if (i == 0)
1125
318
  return 0;
1126
0
    slen += (i + 1) * sizeof (FcChar8 *);
1127
0
    if (slen <= size_bytes)
1128
0
  newp = buf;
1129
0
    else {
1130
0
  newp = malloc (slen);
1131
0
  if (!newp) {
1132
0
      FcConfigMessage (0, FcSevereError, "out of memory");
1133
0
      return 0;
1134
0
  }
1135
0
    }
1136
0
    s = (FcChar8 *)(newp + (i + 1));
1137
0
    for (i = 0; attr[i]; i++) {
1138
0
  newp[i] = s;
1139
0
  strcpy ((char *)s, (char *)attr[i]);
1140
0
  s += strlen ((char *)s) + 1;
1141
0
    }
1142
0
    newp[i] = 0;
1143
0
    return newp;
1144
0
}
1145
1146
static FcBool
1147
FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1148
318
{
1149
318
    FcPStack *newp;
1150
1151
318
    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1152
318
  newp = &parse->pstack_static[parse->pstack_static_used++];
1153
0
    else {
1154
0
  newp = malloc (sizeof (FcPStack));
1155
0
  if (!newp)
1156
0
      return FcFalse;
1157
0
    }
1158
1159
318
    newp->prev = parse->pstack;
1160
318
    newp->element = element;
1161
318
    newp->attr = FcConfigSaveAttr (attr, newp->attr_buf_static, sizeof (newp->attr_buf_static));
1162
318
    FcStrBufInit (&newp->str, 0, 0);
1163
318
    parse->pstack = newp;
1164
318
    return FcTrue;
1165
318
}
1166
1167
static FcBool
1168
FcPStackPop (FcConfigParse *parse)
1169
318
{
1170
318
    FcPStack *old;
1171
1172
318
    if (!parse->pstack) {
1173
0
  FcConfigMessage (parse, FcSevereError, "mismatching element");
1174
0
  return FcFalse;
1175
0
    }
1176
1177
    /* Don't check the attributes for FcElementNone */
1178
318
    if (parse->pstack->element != FcElementNone &&
1179
318
        parse->pstack->attr) {
1180
  /* Warn about unused attrs. */
1181
0
  FcChar8 **attrs = parse->pstack->attr;
1182
0
  while (*attrs) {
1183
0
      if (attrs[0][0]) {
1184
0
    FcConfigMessage (parse, FcSevereWarning, "invalid attribute '%s'", attrs[0]);
1185
0
      }
1186
0
      attrs += 2;
1187
0
  }
1188
0
    }
1189
1190
318
    FcVStackClear (parse);
1191
318
    old = parse->pstack;
1192
318
    parse->pstack = old->prev;
1193
318
    FcStrBufDestroy (&old->str);
1194
1195
318
    if (old->attr && old->attr != old->attr_buf_static)
1196
0
  free (old->attr);
1197
1198
318
    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1199
318
  parse->pstack_static_used--;
1200
0
    else
1201
0
  free (old);
1202
318
    return FcTrue;
1203
318
}
1204
1205
static FcBool
1206
FcConfigParseInit (FcConfigParse *parse,
1207
                   const FcChar8 *name,
1208
                   FcConfig      *config,
1209
                   XML_Parser     parser,
1210
                   FcBool         enabled)
1211
106
{
1212
106
    parse->pstack = 0;
1213
106
    parse->pstack_static_used = 0;
1214
106
    parse->vstack = 0;
1215
106
    parse->vstack_static_used = 0;
1216
106
    parse->error = FcFalse;
1217
106
    parse->name = name;
1218
106
    parse->config = config;
1219
106
    parse->ruleset = FcRuleSetCreate (name);
1220
106
    parse->parser = parser;
1221
106
    parse->scanOnly = !enabled;
1222
106
    FcRuleSetEnable (parse->ruleset, enabled);
1223
1224
106
    return FcTrue;
1225
106
}
1226
1227
static void
1228
FcConfigCleanup (FcConfigParse *parse)
1229
106
{
1230
106
    while (parse->pstack)
1231
0
  FcPStackPop (parse);
1232
106
    FcRuleSetDestroy (parse->ruleset);
1233
106
    parse->ruleset = NULL;
1234
106
}
1235
1236
static const FcChar8 *
1237
FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1238
318
{
1239
318
    FcChar8 **attrs;
1240
318
    if (!parse->pstack)
1241
0
  return 0;
1242
1243
318
    attrs = parse->pstack->attr;
1244
318
    if (!attrs)
1245
318
  return 0;
1246
1247
0
    while (*attrs) {
1248
0
  if (!strcmp ((char *)*attrs, attr)) {
1249
0
      attrs[0][0] = '\0'; /* Mark as used. */
1250
0
      return attrs[1];
1251
0
  }
1252
0
  attrs += 2;
1253
0
    }
1254
0
    return 0;
1255
0
}
1256
1257
static FcStrSet *
1258
_get_real_paths_from_prefix (FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix)
1259
106
{
1260
#ifdef _WIN32
1261
    FcChar8 buffer[1000] = { 0 };
1262
#endif
1263
106
    FcChar8  *parent = NULL, *retval = NULL;
1264
106
    FcStrSet *e = NULL;
1265
1266
106
    if (prefix) {
1267
0
  if (FcStrCmp (prefix, (const FcChar8 *)"xdg") == 0) {
1268
0
      parent = FcConfigXdgDataHome();
1269
0
      if (!parent) {
1270
    /* Home directory might be disabled */
1271
0
    return NULL;
1272
0
      }
1273
0
      e = FcConfigXdgDataDirs();
1274
0
      if (!e) {
1275
0
    FcStrFree (parent);
1276
0
    return NULL;
1277
0
      }
1278
0
  } else if (FcStrCmp (prefix, (const FcChar8 *)"default") == 0 ||
1279
0
             FcStrCmp (prefix, (const FcChar8 *)"cwd") == 0) {
1280
      /* Nothing to do */
1281
0
  } else if (FcStrCmp (prefix, (const FcChar8 *)"relative") == 0) {
1282
0
      FcChar8 *p = FcStrRealPath (parse->name);
1283
1284
0
      if (!p)
1285
0
    return NULL;
1286
0
      parent = FcStrDirname (p);
1287
0
      FcStrFree (p);
1288
0
      if (!parent)
1289
0
    return NULL;
1290
0
  }
1291
0
    }
1292
106
#ifndef _WIN32
1293
    /* For Win32, check this later for dealing with special cases */
1294
106
    else {
1295
106
  if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1296
0
      FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1297
106
    }
1298
#else
1299
    if (strcmp ((const char *)path, "CUSTOMFONTDIR") == 0) {
1300
  FcChar8 *p;
1301
  path = buffer;
1302
  if (!GetModuleFileName (NULL, (LPCH)buffer, sizeof (buffer) - 20)) {
1303
      FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1304
      return NULL;
1305
  }
1306
  /*
1307
   * Must use the multi-byte aware function to search
1308
   * for backslash because East Asian double-byte code
1309
   * pages have characters with backslash as the second
1310
   * byte.
1311
   */
1312
  p = _mbsrchr (path, '\\');
1313
  if (p)
1314
      *p = '\0';
1315
  strcat ((char *)path, "\\fonts");
1316
    } else if (strcmp ((const char *)path, "APPSHAREFONTDIR") == 0) {
1317
  FcChar8 *p;
1318
  path = buffer;
1319
  if (!GetModuleFileName (NULL, (LPCH)buffer, sizeof (buffer) - 20)) {
1320
      FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1321
      return NULL;
1322
  }
1323
  p = _mbsrchr (path, '\\');
1324
  if (p)
1325
      *p = '\0';
1326
  strcat ((char *)path, "\\..\\share\\fonts");
1327
    } else if (strcmp ((const char *)path, "WINDOWSUSERFONTDIR") == 0) {
1328
  path = buffer;
1329
  if (!(pSHGetFolderPathA && SUCCEEDED (pSHGetFolderPathA (NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, (char *)buffer)))) {
1330
      FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
1331
      return NULL;
1332
  }
1333
  strcat ((char *)path, "\\Microsoft\\Windows\\Fonts");
1334
    } else if (strcmp ((const char *)path, "WINDOWSFONTDIR") == 0) {
1335
  int rc;
1336
  path = buffer;
1337
  _ensureWin32GettersReady();
1338
  rc = pGetSystemWindowsDirectory ((LPSTR)buffer, sizeof (buffer) - 20);
1339
  if (rc == 0 || rc > sizeof (buffer) - 20) {
1340
      FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
1341
      return NULL;
1342
  }
1343
  if (path[strlen ((const char *)path) - 1] != '\\')
1344
      strcat ((char *)path, "\\");
1345
  strcat ((char *)path, "fonts");
1346
    } else {
1347
  if (!prefix) {
1348
      if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1349
    FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1350
  }
1351
    }
1352
#endif
1353
106
    if (parent) {
1354
0
  retval = FcStrBuildFilename (parent, path, NULL);
1355
0
  FcStrFree (parent);
1356
106
    } else {
1357
106
  retval = FcStrdup (path);
1358
106
    }
1359
106
    if (!e)
1360
106
  e = FcStrSetCreate();
1361
0
    else {
1362
0
  FcChar8 *s;
1363
0
  int      i;
1364
1365
0
  for (i = 0; i < e->num; i++) {
1366
0
      s = FcStrBuildFilename (e->strs[i], path, NULL);
1367
0
      FcStrFree (e->strs[i]);
1368
0
      e->strs[i] = s;
1369
0
  }
1370
0
    }
1371
106
    if (!FcStrSetInsert (e, retval, 0)) {
1372
0
  FcStrSetDestroy (e);
1373
0
  e = NULL;
1374
0
    }
1375
106
    FcStrFree (retval);
1376
1377
106
    return e;
1378
106
}
1379
1380
static void
1381
FcStartElement (void *userData, const XML_Char *name, const XML_Char **attr)
1382
318
{
1383
318
    FcConfigParse *parse = userData;
1384
318
    FcElement      element;
1385
1386
318
    element = FcElementMap (name);
1387
318
    if (element == FcElementUnknown)
1388
0
  FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1389
1390
318
    if (!FcPStackPush (parse, element, attr)) {
1391
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1392
0
  return;
1393
0
    }
1394
318
    return;
1395
318
}
1396
1397
static void
1398
FcParseRescan (FcConfigParse *parse)
1399
0
{
1400
0
    int n = FcVStackElements (parse);
1401
0
    while (n-- > 0) {
1402
0
  FcVStack *v = FcVStackFetch (parse, n);
1403
0
  if (v->tag != FcVStackInteger)
1404
0
      FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1405
0
  else
1406
0
      parse->config->rescanInterval = v->u.integer;
1407
0
    }
1408
0
}
1409
1410
static void
1411
FcParseInt (FcConfigParse *parse)
1412
0
{
1413
0
    FcChar8 *s, *end;
1414
0
    int      l;
1415
1416
0
    if (!parse->pstack)
1417
0
  return;
1418
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1419
0
    if (!s) {
1420
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1421
0
  return;
1422
0
    }
1423
0
    end = 0;
1424
0
    l = (int)strtol ((char *)s, (char **)&end, 0);
1425
0
    if (end != s + strlen ((char *)s))
1426
0
  FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1427
0
    else
1428
0
  FcVStackPushInteger (parse, l);
1429
0
    FcStrBufDestroy (&parse->pstack->str);
1430
0
}
1431
1432
/*
1433
 * idea copied from glib g_ascii_strtod with
1434
 * permission of the author (Alexander Larsson)
1435
 */
1436
1437
#include <locale.h>
1438
1439
static double
1440
FcStrtod (char *s, char **end)
1441
0
{
1442
0
#ifndef __BIONIC__
1443
0
    struct lconv *locale_data;
1444
0
#endif
1445
0
    const char *decimal_point;
1446
0
    int         dlen;
1447
0
    char       *dot;
1448
0
    double      v;
1449
1450
    /*
1451
     * Have to swap the decimal point to match the current locale
1452
     * if that locale doesn't use 0x2e
1453
     */
1454
0
#ifndef __BIONIC__
1455
0
    locale_data = localeconv();
1456
0
    decimal_point = locale_data->decimal_point;
1457
0
    dlen = strlen (decimal_point);
1458
#else
1459
    decimal_point = ".";
1460
    dlen = 1;
1461
#endif
1462
1463
0
    if ((dot = strchr (s, 0x2e)) &&
1464
0
        (decimal_point[0] != 0x2e ||
1465
0
         decimal_point[1] != 0)) {
1466
0
  char buf[128];
1467
0
  int  slen = strlen (s);
1468
1469
0
  if (slen + dlen > (int)sizeof (buf)) {
1470
0
      if (end)
1471
0
    *end = s;
1472
0
      v = 0;
1473
0
  } else {
1474
0
      char *buf_end;
1475
      /* mantissa */
1476
0
      strncpy (buf, s, dot - s);
1477
      /* decimal point */
1478
0
      strcpy (buf + (dot - s), decimal_point);
1479
      /* rest of number */
1480
0
      strcpy (buf + (dot - s) + dlen, dot + 1);
1481
0
      buf_end = 0;
1482
0
      v = strtod (buf, &buf_end);
1483
0
      if (buf_end) {
1484
0
    buf_end = s + (buf_end - buf);
1485
0
    if (buf_end > dot)
1486
0
        buf_end -= dlen - 1;
1487
0
      }
1488
0
      if (end)
1489
0
    *end = buf_end;
1490
0
  }
1491
0
    } else
1492
0
  v = strtod (s, end);
1493
0
    return v;
1494
0
}
1495
1496
static void
1497
FcParseDouble (FcConfigParse *parse)
1498
0
{
1499
0
    FcChar8 *s, *end;
1500
0
    double   d;
1501
1502
0
    if (!parse->pstack)
1503
0
  return;
1504
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1505
0
    if (!s) {
1506
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1507
0
  return;
1508
0
    }
1509
0
    end = 0;
1510
0
    d = FcStrtod ((char *)s, (char **)&end);
1511
0
    if (end != s + strlen ((char *)s))
1512
0
  FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1513
0
    else
1514
0
  FcVStackPushDouble (parse, d);
1515
0
    FcStrBufDestroy (&parse->pstack->str);
1516
0
}
1517
1518
static void
1519
FcParseString (FcConfigParse *parse, FcVStackTag tag)
1520
0
{
1521
0
    FcChar8 *s;
1522
1523
0
    if (!parse->pstack)
1524
0
  return;
1525
0
    s = FcStrBufDone (&parse->pstack->str);
1526
0
    if (!s) {
1527
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1528
0
  return;
1529
0
    }
1530
0
    if (!FcVStackPushString (parse, tag, s))
1531
0
  FcStrFree (s);
1532
0
}
1533
1534
static void
1535
FcParseName (FcConfigParse *parse)
1536
0
{
1537
0
    const FcChar8 *kind_string;
1538
0
    FcMatchKind    kind;
1539
0
    FcChar8       *s;
1540
0
    FcObject       object;
1541
1542
0
    kind_string = FcConfigGetAttribute (parse, "target");
1543
0
    if (!kind_string)
1544
0
  kind = FcMatchDefault;
1545
0
    else {
1546
0
  if (!strcmp ((char *)kind_string, "pattern"))
1547
0
      kind = FcMatchPattern;
1548
0
  else if (!strcmp ((char *)kind_string, "font"))
1549
0
      kind = FcMatchFont;
1550
0
  else if (!strcmp ((char *)kind_string, "default"))
1551
0
      kind = FcMatchDefault;
1552
0
  else {
1553
0
      FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1554
0
      return;
1555
0
  }
1556
0
    }
1557
1558
0
    if (!parse->pstack)
1559
0
  return;
1560
0
    s = FcStrBufDone (&parse->pstack->str);
1561
0
    if (!s) {
1562
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1563
0
  return;
1564
0
    }
1565
0
    object = FcObjectFromName ((const char *)s);
1566
1567
0
    FcVStackPushName (parse, kind, object);
1568
1569
0
    FcStrFree (s);
1570
0
}
1571
1572
static void
1573
FcParseMatrix (FcConfigParse *parse)
1574
0
{
1575
0
    FcExprMatrix m;
1576
1577
0
    m.yy = FcPopExpr (parse);
1578
0
    m.yx = FcPopExpr (parse);
1579
0
    m.xy = FcPopExpr (parse);
1580
0
    m.xx = FcPopExpr (parse);
1581
1582
0
    if (!m.yy || !m.yx || !m.xy || !m.xx) {
1583
0
  FcConfigMessage (parse, FcSevereWarning, "Missing values in matrix element");
1584
0
  return;
1585
0
    }
1586
0
    if (FcPopExpr (parse))
1587
0
  FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1588
0
    else
1589
0
  FcVStackPushMatrix (parse, &m);
1590
0
}
1591
1592
static void
1593
FcParseRange (FcConfigParse *parse)
1594
0
{
1595
0
    FcVStack *vstack;
1596
0
    FcRange  *r;
1597
0
    FcChar32  n[2] = { 0, 0 };
1598
0
    int       count = 1;
1599
0
    double    d[2] = { 0.0L, 0.0L };
1600
0
    FcBool    dflag = FcFalse;
1601
1602
0
    while ((vstack = FcVStackPeek (parse))) {
1603
0
  if (count < 0) {
1604
0
      FcConfigMessage (parse, FcSevereError, "too many elements in range");
1605
0
      return;
1606
0
  }
1607
0
  switch ((int)vstack->tag) {
1608
0
  case FcVStackInteger:
1609
0
      if (dflag)
1610
0
    d[count] = (double)vstack->u.integer;
1611
0
      else
1612
0
    n[count] = vstack->u.integer;
1613
0
      break;
1614
0
  case FcVStackDouble:
1615
0
      if (count == 0 && !dflag)
1616
0
    d[1] = (double)n[1];
1617
0
      d[count] = vstack->u._double;
1618
0
      dflag = FcTrue;
1619
0
      break;
1620
0
  default:
1621
0
      FcConfigMessage (parse, FcSevereError, "invalid element in range");
1622
0
      if (dflag)
1623
0
    d[count] = 0.0L;
1624
0
      else
1625
0
    n[count] = 0;
1626
0
      break;
1627
0
  }
1628
0
  count--;
1629
0
  FcVStackPopAndDestroy (parse);
1630
0
    }
1631
0
    if (count >= 0) {
1632
0
  FcConfigMessage (parse, FcSevereError, "invalid range");
1633
0
  return;
1634
0
    }
1635
0
    if (dflag) {
1636
0
  if (d[0] > d[1]) {
1637
0
      FcConfigMessage (parse, FcSevereError, "invalid range");
1638
0
      return;
1639
0
  }
1640
0
  r = FcRangeCreateDouble (d[0], d[1]);
1641
0
    } else {
1642
0
  if (n[0] > n[1]) {
1643
0
      FcConfigMessage (parse, FcSevereError, "invalid range");
1644
0
      return;
1645
0
  }
1646
0
  r = FcRangeCreateInteger (n[0], n[1]);
1647
0
    }
1648
0
    FcVStackPushRange (parse, r);
1649
0
}
1650
1651
static FcBool
1652
FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1653
0
{
1654
0
    FcBool result = FcFalse;
1655
1656
0
    if (!FcNameBool (bool_, &result))
1657
0
  FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1658
0
                   bool_);
1659
0
    return result;
1660
0
}
1661
1662
static void
1663
FcParseBool (FcConfigParse *parse)
1664
0
{
1665
0
    FcChar8 *s;
1666
1667
0
    if (!parse->pstack)
1668
0
  return;
1669
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1670
0
    if (!s) {
1671
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1672
0
  return;
1673
0
    }
1674
0
    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1675
0
    FcStrBufDestroy (&parse->pstack->str);
1676
0
}
1677
1678
static void
1679
FcParseCharSet (FcConfigParse *parse)
1680
0
{
1681
0
    FcVStack  *vstack;
1682
0
    FcCharSet *charset = FcCharSetCreate();
1683
0
    FcChar32   i, begin, end;
1684
0
    int        n = 0;
1685
1686
0
    while ((vstack = FcVStackPeek (parse))) {
1687
0
  switch ((int)vstack->tag) {
1688
0
  case FcVStackInteger:
1689
0
      if (!FcCharSetAddChar (charset, vstack->u.integer)) {
1690
0
    FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1691
0
      } else
1692
0
    n++;
1693
0
      break;
1694
0
  case FcVStackRange:
1695
0
      begin = (FcChar32)vstack->u.range->begin;
1696
0
      end = (FcChar32)vstack->u.range->end;
1697
1698
0
      if (begin <= end) {
1699
0
    for (i = begin; i <= end; i++) {
1700
0
        if (!FcCharSetAddChar (charset, i)) {
1701
0
      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1702
0
        } else
1703
0
      n++;
1704
0
    }
1705
0
      }
1706
0
      break;
1707
0
  default:
1708
0
      FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1709
0
      break;
1710
0
  }
1711
0
  FcVStackPopAndDestroy (parse);
1712
0
    }
1713
0
    if (n > 0)
1714
0
  FcVStackPushCharSet (parse, charset);
1715
0
    else
1716
0
  FcCharSetDestroy (charset);
1717
0
}
1718
1719
static void
1720
FcParseLangSet (FcConfigParse *parse)
1721
0
{
1722
0
    FcVStack  *vstack;
1723
0
    FcLangSet *langset = FcLangSetCreate();
1724
0
    int        n = 0;
1725
1726
0
    while ((vstack = FcVStackPeek (parse))) {
1727
0
  switch ((int)vstack->tag) {
1728
0
  case FcVStackString:
1729
0
      if (!FcLangSetAdd (langset, vstack->u.string)) {
1730
0
    FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1731
0
      } else
1732
0
    n++;
1733
0
      break;
1734
0
  default:
1735
0
      FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1736
0
      break;
1737
0
  }
1738
0
  FcVStackPopAndDestroy (parse);
1739
0
    }
1740
0
    if (n > 0)
1741
0
  FcVStackPushLangSet (parse, langset);
1742
0
    else
1743
0
  FcLangSetDestroy (langset);
1744
0
}
1745
1746
static FcBool
1747
FcConfigLexBinding (FcConfigParse  *parse,
1748
                    const FcChar8  *binding_string,
1749
                    FcValueBinding *binding_ret)
1750
0
{
1751
0
    FcValueBinding binding;
1752
1753
0
    if (!binding_string)
1754
0
  binding = FcValueBindingWeak;
1755
0
    else {
1756
0
  if (!strcmp ((char *)binding_string, "weak"))
1757
0
      binding = FcValueBindingWeak;
1758
0
  else if (!strcmp ((char *)binding_string, "strong"))
1759
0
      binding = FcValueBindingStrong;
1760
0
  else if (!strcmp ((char *)binding_string, "same"))
1761
0
      binding = FcValueBindingSame;
1762
0
  else {
1763
0
      FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1764
0
      return FcFalse;
1765
0
  }
1766
0
    }
1767
0
    *binding_ret = binding;
1768
0
    return FcTrue;
1769
0
}
1770
1771
static void
1772
FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1773
0
{
1774
0
    FcVStack *vstack;
1775
0
    FcExpr   *left, *expr = 0, *newp;
1776
1777
0
    while ((vstack = FcVStackPeek (parse))) {
1778
0
  if (vstack->tag != FcVStackFamily) {
1779
0
      FcConfigMessage (parse, FcSevereWarning, "non-family");
1780
0
      FcVStackPopAndDestroy (parse);
1781
0
      continue;
1782
0
  }
1783
0
  left = vstack->u.expr;
1784
0
  vstack->tag = FcVStackNone;
1785
0
  FcVStackPopAndDestroy (parse);
1786
0
  if (expr) {
1787
0
      newp = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1788
0
      if (!newp) {
1789
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
1790
0
    FcExprDestroy (left);
1791
0
    FcExprDestroy (expr);
1792
0
    break;
1793
0
      }
1794
0
      expr = newp;
1795
0
  } else
1796
0
      expr = left;
1797
0
    }
1798
0
    if (expr) {
1799
0
  if (!FcVStackPushExpr (parse, tag, expr)) {
1800
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
1801
0
      FcExprDestroy (expr);
1802
0
  }
1803
0
    }
1804
0
}
1805
1806
static void
1807
FcParseFamily (FcConfigParse *parse)
1808
0
{
1809
0
    FcChar8 *s;
1810
0
    FcExpr  *expr;
1811
1812
0
    if (!parse->pstack)
1813
0
  return;
1814
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1815
0
    if (!s) {
1816
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1817
0
  return;
1818
0
    }
1819
0
    expr = FcExprCreateString (parse->config, s);
1820
0
    FcStrBufDestroy (&parse->pstack->str);
1821
0
    if (expr)
1822
0
  FcVStackPushExpr (parse, FcVStackFamily, expr);
1823
0
}
1824
1825
static void
1826
FcParseAlias (FcConfigParse *parse)
1827
0
{
1828
0
    FcExpr        *family = 0, *accept = 0, *prefer = 0, *def = 0, *newp = 0;
1829
0
    FcEdit        *edit = 0;
1830
0
    FcVStack      *vstack;
1831
0
    FcRule        *rule = NULL, *r;
1832
0
    FcValueBinding binding;
1833
0
    int            n;
1834
1835
0
    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1836
0
  return;
1837
0
    while ((vstack = FcVStackPeek (parse))) {
1838
0
  switch ((int)vstack->tag) {
1839
0
  case FcVStackFamily:
1840
0
      if (family) {
1841
0
    FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1842
0
    newp = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1843
0
    if (!newp)
1844
0
        FcConfigMessage (parse, FcSevereError, "out of memory");
1845
0
    else
1846
0
        family = newp;
1847
0
      } else
1848
0
    newp = vstack->u.expr;
1849
0
      if (newp) {
1850
0
    family = newp;
1851
0
    vstack->tag = FcVStackNone;
1852
0
      }
1853
0
      break;
1854
0
  case FcVStackPrefer:
1855
0
      if (prefer)
1856
0
    FcExprDestroy (prefer);
1857
0
      prefer = vstack->u.expr;
1858
0
      vstack->tag = FcVStackNone;
1859
0
      break;
1860
0
  case FcVStackAccept:
1861
0
      if (accept)
1862
0
    FcExprDestroy (accept);
1863
0
      accept = vstack->u.expr;
1864
0
      vstack->tag = FcVStackNone;
1865
0
      break;
1866
0
  case FcVStackDefault:
1867
0
      if (def)
1868
0
    FcExprDestroy (def);
1869
0
      def = vstack->u.expr;
1870
0
      vstack->tag = FcVStackNone;
1871
0
      break;
1872
0
  case FcVStackTest:
1873
0
      if (rule) {
1874
0
    r = FcRuleCreate (FcRuleTest, vstack->u.test);
1875
0
    r->next = rule;
1876
0
    rule = r;
1877
0
      } else
1878
0
    rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1879
0
      vstack->tag = FcVStackNone;
1880
0
      break;
1881
0
  default:
1882
0
      FcConfigMessage (parse, FcSevereWarning, "bad alias");
1883
0
      break;
1884
0
  }
1885
0
  FcVStackPopAndDestroy (parse);
1886
0
    }
1887
0
    if (!family) {
1888
0
  FcConfigMessage (parse, FcSevereError, "missing family in alias");
1889
0
  if (prefer)
1890
0
      FcExprDestroy (prefer);
1891
0
  if (accept)
1892
0
      FcExprDestroy (accept);
1893
0
  if (def)
1894
0
      FcExprDestroy (def);
1895
0
  if (rule)
1896
0
      FcRuleDestroy (rule);
1897
0
  return;
1898
0
    }
1899
0
    if (!prefer &&
1900
0
        !accept &&
1901
0
        !def) {
1902
0
  FcExprDestroy (family);
1903
0
  if (rule)
1904
0
      FcRuleDestroy (rule);
1905
0
  return;
1906
0
    } else {
1907
0
  FcTest *t = FcTestCreate (parse, FcMatchPattern,
1908
0
                            FcQualAny,
1909
0
                            (FcChar8 *)FC_FAMILY,
1910
0
                            FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1911
0
                            family);
1912
0
  if (rule) {
1913
0
      for (r = rule; r->next; r = r->next)
1914
0
    ;
1915
0
      r->next = FcRuleCreate (FcRuleTest, t);
1916
0
      r = r->next;
1917
0
  } else {
1918
0
      r = rule = FcRuleCreate (FcRuleTest, t);
1919
0
  }
1920
0
    }
1921
0
    if (prefer) {
1922
0
  edit = FcEditCreate (parse,
1923
0
                       FC_FAMILY_OBJECT,
1924
0
                       FcOpPrepend,
1925
0
                       prefer,
1926
0
                       binding);
1927
0
  if (!edit)
1928
0
      FcExprDestroy (prefer);
1929
0
  else {
1930
0
      r->next = FcRuleCreate (FcRuleEdit, edit);
1931
0
      r = r->next;
1932
0
  }
1933
0
    }
1934
0
    if (accept) {
1935
0
  edit = FcEditCreate (parse,
1936
0
                       FC_FAMILY_OBJECT,
1937
0
                       FcOpAppend,
1938
0
                       accept,
1939
0
                       binding);
1940
0
  if (!edit)
1941
0
      FcExprDestroy (accept);
1942
0
  else {
1943
0
      r->next = FcRuleCreate (FcRuleEdit, edit);
1944
0
      r = r->next;
1945
0
  }
1946
0
    }
1947
0
    if (def) {
1948
0
  edit = FcEditCreate (parse,
1949
0
                       FC_FAMILY_OBJECT,
1950
0
                       FcOpAppendLast,
1951
0
                       def,
1952
0
                       binding);
1953
0
  if (!edit)
1954
0
      FcExprDestroy (def);
1955
0
  else {
1956
0
      r->next = FcRuleCreate (FcRuleEdit, edit);
1957
0
      r = r->next;
1958
0
  }
1959
0
    }
1960
0
    if ((n = FcRuleSetAdd (parse->ruleset, rule, FcMatchPattern)) == -1)
1961
0
  FcRuleDestroy (rule);
1962
0
    else if (parse->config->maxObjects < n)
1963
0
  parse->config->maxObjects = n;
1964
0
}
1965
1966
static void
1967
FcParseDescription (FcConfigParse *parse)
1968
0
{
1969
0
    const FcChar8 *domain;
1970
0
    FcChar8       *desc;
1971
1972
0
    domain = FcConfigGetAttribute (parse, "domain");
1973
0
    desc = FcStrBufDone (&parse->pstack->str);
1974
0
    if (!desc) {
1975
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1976
0
  return;
1977
0
    }
1978
0
    FcRuleSetAddDescription (parse->ruleset, domain, desc);
1979
1980
0
    FcStrFree (desc);
1981
0
}
1982
1983
static void
1984
FcParseRemapDir (FcConfigParse *parse)
1985
0
{
1986
0
    const FcChar8 *path, *attr, *data, *salt;
1987
0
    FcStrSet      *prefix_dirs = NULL;
1988
1989
0
    data = FcStrBufDoneStatic (&parse->pstack->str);
1990
0
    if (!data) {
1991
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1992
0
  return;
1993
0
    }
1994
0
    if (data[0] == 0) {
1995
0
  FcConfigMessage (parse, FcSevereWarning, "empty font directory name for remap ignored");
1996
0
  return;
1997
0
    }
1998
0
    path = FcConfigGetAttribute (parse, "as-path");
1999
0
    if (!path) {
2000
0
  FcConfigMessage (parse, FcSevereWarning, "Missing as-path in remap-dir");
2001
0
  return;
2002
0
    }
2003
0
    attr = FcConfigGetAttribute (parse, "prefix");
2004
0
    salt = FcConfigGetAttribute (parse, "salt");
2005
0
    prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2006
0
    if (prefix_dirs) {
2007
0
  FcStrList *l = FcStrListCreate (prefix_dirs);
2008
0
  FcChar8   *prefix;
2009
2010
0
  FcStrSetDestroy (prefix_dirs);
2011
0
  while ((prefix = FcStrListNext (l))) {
2012
0
      if (!prefix || prefix[0] == 0) {
2013
    /* nop */
2014
0
      } else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome())) {
2015
0
    if (!FcConfigAddFontDir (parse->config, prefix, path, salt))
2016
0
        FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path);
2017
0
      }
2018
0
      FcStrBufDestroy (&parse->pstack->str);
2019
0
  }
2020
0
  FcStrListDone (l);
2021
0
    }
2022
0
}
2023
2024
static void
2025
FcParseResetDirs (FcConfigParse *parse)
2026
0
{
2027
0
    if (!parse->scanOnly) {
2028
0
  if (!FcConfigResetFontDirs (parse->config))
2029
0
      FcConfigMessage (parse, FcSevereError, "Unable to reset fonts dirs");
2030
0
    }
2031
0
}
2032
2033
static FcExpr *
2034
FcPopExpr (FcConfigParse *parse)
2035
0
{
2036
0
    FcVStack *vstack = FcVStackPeek (parse);
2037
0
    FcExpr   *expr = 0;
2038
0
    if (!vstack)
2039
0
  return 0;
2040
0
    switch ((int)vstack->tag) {
2041
0
    case FcVStackNone:
2042
0
  break;
2043
0
    case FcVStackString:
2044
0
    case FcVStackFamily:
2045
0
  expr = FcExprCreateString (parse->config, vstack->u.string);
2046
0
  break;
2047
0
    case FcVStackName:
2048
0
  expr = FcExprCreateName (parse->config, vstack->u.name);
2049
0
  break;
2050
0
    case FcVStackConstant:
2051
0
  expr = FcExprCreateConst (parse->config, vstack->u.string);
2052
0
  break;
2053
0
    case FcVStackGlob:
2054
  /* XXX: What's the correct action here? (CDW) */
2055
0
  break;
2056
0
    case FcVStackPrefer:
2057
0
    case FcVStackAccept:
2058
0
    case FcVStackDefault:
2059
0
  expr = vstack->u.expr;
2060
0
  vstack->tag = FcVStackNone;
2061
0
  break;
2062
0
    case FcVStackInteger:
2063
0
  expr = FcExprCreateInteger (parse->config, vstack->u.integer);
2064
0
  break;
2065
0
    case FcVStackDouble:
2066
0
  expr = FcExprCreateDouble (parse->config, vstack->u._double);
2067
0
  break;
2068
0
    case FcVStackMatrix:
2069
0
  expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
2070
0
  break;
2071
0
    case FcVStackRange:
2072
0
  expr = FcExprCreateRange (parse->config, vstack->u.range);
2073
0
  break;
2074
0
    case FcVStackBool:
2075
0
  expr = FcExprCreateBool (parse->config, vstack->u.bool_);
2076
0
  break;
2077
0
    case FcVStackCharSet:
2078
0
  expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
2079
0
  break;
2080
0
    case FcVStackLangSet:
2081
0
  expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
2082
0
  break;
2083
0
    case FcVStackTest:
2084
0
  break;
2085
0
    case FcVStackExpr:
2086
0
  expr = vstack->u.expr;
2087
0
  vstack->tag = FcVStackNone;
2088
0
  break;
2089
0
    case FcVStackEdit:
2090
0
  break;
2091
0
    default:
2092
0
  break;
2093
0
    }
2094
0
    FcVStackPopAndDestroy (parse);
2095
0
    return expr;
2096
0
}
2097
2098
/*
2099
 * This builds a tree of binary operations.  Note
2100
 * that every operator is defined so that if only
2101
 * a single operand is contained, the value of the
2102
 * whole expression is the value of the operand.
2103
 *
2104
 * This code reduces in that case to returning that
2105
 * operand.
2106
 */
2107
static FcExpr *
2108
FcPopBinary (FcConfigParse *parse, FcOp op)
2109
0
{
2110
0
    FcExpr *left, *expr = 0, *newp;
2111
2112
0
    while ((left = FcPopExpr (parse))) {
2113
0
  if (expr) {
2114
0
      newp = FcExprCreateOp (parse->config, left, op, expr);
2115
0
      if (!newp) {
2116
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
2117
0
    FcExprDestroy (left);
2118
0
    FcExprDestroy (expr);
2119
0
    return 0;
2120
0
      }
2121
0
      expr = newp;
2122
0
  } else
2123
0
      expr = left;
2124
0
    }
2125
0
    return expr;
2126
0
}
2127
2128
static void
2129
FcParseBinary (FcConfigParse *parse, FcOp op)
2130
0
{
2131
0
    FcExpr *expr = FcPopBinary (parse, op);
2132
0
    if (expr)
2133
0
  FcVStackPushExpr (parse, FcVStackExpr, expr);
2134
0
}
2135
2136
/*
2137
 * This builds a a unary operator, it consumes only
2138
 * a single operand
2139
 */
2140
2141
static FcExpr *
2142
FcPopUnary (FcConfigParse *parse, FcOp op)
2143
0
{
2144
0
    FcExpr *operand, *newp = 0;
2145
2146
0
    if ((operand = FcPopExpr (parse))) {
2147
0
  newp = FcExprCreateOp (parse->config, operand, op, 0);
2148
0
  if (!newp) {
2149
0
      FcExprDestroy (operand);
2150
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2151
0
  }
2152
0
    }
2153
0
    return newp;
2154
0
}
2155
2156
static void
2157
FcParseUnary (FcConfigParse *parse, FcOp op)
2158
0
{
2159
0
    FcExpr *expr = FcPopUnary (parse, op);
2160
0
    if (expr)
2161
0
  FcVStackPushExpr (parse, FcVStackExpr, expr);
2162
0
}
2163
2164
static void
2165
FcParseDir (FcConfigParse *parse)
2166
106
{
2167
106
    const FcChar8 *attr, *data, *salt;
2168
106
    FcStrSet      *prefix_dirs = NULL;
2169
2170
106
    data = FcStrBufDoneStatic (&parse->pstack->str);
2171
106
    if (!data) {
2172
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2173
0
  return;
2174
0
    }
2175
106
    if (data[0] == 0) {
2176
0
  FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2177
0
  return;
2178
0
    }
2179
106
    attr = FcConfigGetAttribute (parse, "prefix");
2180
106
    salt = FcConfigGetAttribute (parse, "salt");
2181
106
    prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2182
106
    if (prefix_dirs) {
2183
106
  FcStrList *l = FcStrListCreate (prefix_dirs);
2184
106
  FcChar8   *prefix;
2185
2186
106
  FcStrSetDestroy (prefix_dirs);
2187
212
  while ((prefix = FcStrListNext (l))) {
2188
106
      if (!prefix || prefix[0] == 0) {
2189
    /* nop */
2190
106
      } else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome())) {
2191
106
    if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt))
2192
0
        FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix);
2193
106
      }
2194
106
      FcStrBufDestroy (&parse->pstack->str);
2195
106
  }
2196
106
  FcStrListDone (l);
2197
106
    }
2198
106
}
2199
2200
static void
2201
FcParseCacheDir (FcConfigParse *parse)
2202
106
{
2203
106
    const FcChar8 *attr;
2204
106
    FcChar8       *prefix = NULL, *p, *data = NULL;
2205
2206
106
    attr = FcConfigGetAttribute (parse, "prefix");
2207
106
    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) {
2208
0
  prefix = FcConfigXdgCacheHome();
2209
  /* home directory might be disabled.
2210
   * simply ignore this element.
2211
   */
2212
0
  if (!prefix)
2213
0
      goto bail;
2214
0
    }
2215
106
    data = FcStrBufDone (&parse->pstack->str);
2216
106
    if (!data) {
2217
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2218
0
  data = prefix;
2219
0
  goto bail;
2220
0
    }
2221
106
    if (data[0] == 0) {
2222
0
  FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2223
0
  FcStrFree (data);
2224
0
  data = prefix;
2225
0
  goto bail;
2226
0
    }
2227
106
    if (prefix) {
2228
0
  size_t plen = strlen ((const char *)prefix);
2229
0
  size_t dlen = strlen ((const char *)data);
2230
2231
0
  p = realloc (prefix, plen + 1 + dlen + 1);
2232
0
  if (!p) {
2233
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2234
0
      FcStrFree (prefix);
2235
0
      goto bail;
2236
0
  }
2237
0
  prefix = p;
2238
0
  prefix[plen] = FC_DIR_SEPARATOR;
2239
0
  memcpy (&prefix[plen + 1], data, dlen);
2240
0
  prefix[plen + 1 + dlen] = 0;
2241
0
  FcStrFree (data);
2242
0
  data = prefix;
2243
0
    }
2244
#ifdef _WIN32
2245
    else if (data[0] == '/' && fontconfig_instprefix[0] != '\0') {
2246
  size_t plen = strlen ((const char *)fontconfig_instprefix);
2247
  size_t dlen = strlen ((const char *)data);
2248
2249
  prefix = malloc (plen + 1 + dlen + 1);
2250
  if (!prefix) {
2251
      FcConfigMessage (parse, FcSevereError, "out of memory");
2252
      goto bail;
2253
  }
2254
  strcpy ((char *)prefix, (char *)fontconfig_instprefix);
2255
  prefix[plen] = FC_DIR_SEPARATOR;
2256
  memcpy (&prefix[plen + 1], data, dlen);
2257
  prefix[plen + 1 + dlen] = 0;
2258
  FcStrFree (data);
2259
  data = prefix;
2260
    } else if (strcmp ((const char *)data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) {
2261
  int rc;
2262
2263
  FcStrFree (data);
2264
  data = malloc (1000);
2265
  if (!data) {
2266
      FcConfigMessage (parse, FcSevereError, "out of memory");
2267
      goto bail;
2268
  }
2269
  rc = GetTempPath (800, (LPSTR)data);
2270
  if (rc == 0 || rc > 800) {
2271
      FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2272
      goto bail;
2273
  }
2274
  if (data[strlen ((const char *)data) - 1] != '\\')
2275
      strcat ((char *)data, "\\");
2276
  strcat ((char *)data, "fontconfig\\cache");
2277
    } else if (strcmp ((const char *)data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0) {
2278
  char   szFPath[MAX_PATH + 1];
2279
  size_t len;
2280
2281
  if (!(pSHGetFolderPathA && SUCCEEDED (pSHGetFolderPathA (NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath)))) {
2282
      FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2283
      goto bail;
2284
  }
2285
  strncat (szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen (szFPath));
2286
  len = strlen (szFPath) + 1;
2287
  FcStrFree (data);
2288
  data = malloc (len);
2289
  if (!data) {
2290
      FcConfigMessage (parse, FcSevereError, "out of memory");
2291
      goto bail;
2292
  }
2293
  strncpy ((char *)data, szFPath, len);
2294
    }
2295
#endif
2296
106
    if (strlen ((char *)data) == 0)
2297
0
  FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2298
106
    else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome())) {
2299
106
  if (!FcConfigAddCacheDir (parse->config, data))
2300
0
      FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2301
106
    }
2302
106
    FcStrBufDestroy (&parse->pstack->str);
2303
2304
106
bail:
2305
106
    if (data)
2306
106
  FcStrFree (data);
2307
106
}
2308
2309
static void
2310
FcParseInclude (FcConfigParse *parse)
2311
0
{
2312
0
    FcChar8       *s;
2313
0
    const FcChar8 *attr;
2314
0
    FcBool         ignore_missing = FcFalse;
2315
0
    FcChar8       *prefix = NULL, *p;
2316
0
    FcRuleSet     *ruleset;
2317
0
    FcMatchKind    k;
2318
2319
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
2320
0
    if (!s) {
2321
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2322
0
  goto bail;
2323
0
    }
2324
0
    attr = FcConfigGetAttribute (parse, "ignore_missing");
2325
0
    if (attr && FcConfigLexBool (parse, (FcChar8 *)attr) == FcTrue)
2326
0
  ignore_missing = FcTrue;
2327
    /* deprecated attribute has ever been used to mark
2328
     * old configuration path as deprecated.
2329
     * We don't have any code for it but just keep it for
2330
     * backward compatibility.
2331
     */
2332
0
    attr = FcConfigGetAttribute (parse, "deprecated");
2333
0
    attr = FcConfigGetAttribute (parse, "prefix");
2334
0
    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) {
2335
0
  prefix = FcConfigXdgConfigHome();
2336
  /* home directory might be disabled.
2337
   * simply ignore this element.
2338
   */
2339
0
  if (!prefix)
2340
0
      goto bail;
2341
0
    }
2342
0
    if (prefix) {
2343
0
  size_t   plen = strlen ((const char *)prefix);
2344
0
  size_t   dlen = strlen ((const char *)s);
2345
2346
0
  p = realloc (prefix, plen + 1 + dlen + 1);
2347
0
  if (!p) {
2348
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2349
0
      goto bail;
2350
0
  }
2351
0
  prefix = p;
2352
0
  prefix[plen] = FC_DIR_SEPARATOR;
2353
0
  memcpy (&prefix[plen + 1], s, dlen);
2354
0
  prefix[plen + 1 + dlen] = 0;
2355
0
  s = prefix;
2356
0
    }
2357
    /* flush the ruleset into the queue */
2358
0
    ruleset = parse->ruleset;
2359
0
    parse->ruleset = FcRuleSetCreate (ruleset->name);
2360
0
    FcRuleSetEnable (parse->ruleset, ruleset->enabled);
2361
0
    FcRuleSetAddDescription (parse->ruleset, ruleset->domain, ruleset->description);
2362
0
    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) {
2363
0
  FcPtrListIter iter;
2364
2365
0
  FcPtrListIterInit (ruleset->subst[k], &iter);
2366
0
  if (FcPtrListIterIsValid (ruleset->subst[k], &iter)) {
2367
0
      FcPtrListIterInitAtLast (parse->config->subst[k], &iter);
2368
0
      FcRuleSetReference (ruleset);
2369
0
      FcPtrListIterAdd (parse->config->subst[k], &iter, ruleset);
2370
0
  }
2371
0
    }
2372
0
    FcRuleSetDestroy (ruleset);
2373
0
    if (!_FcConfigParse (parse->config, s, !ignore_missing, !parse->scanOnly))
2374
0
  parse->error = FcTrue;
2375
0
    FcStrBufDestroy (&parse->pstack->str);
2376
2377
0
bail:
2378
0
    if (prefix)
2379
0
  FcStrFree (prefix);
2380
0
}
2381
2382
typedef struct _FcOpMap {
2383
    char name[16];
2384
    FcOp op;
2385
} FcOpMap;
2386
2387
static FcOp
2388
FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2389
0
{
2390
0
    int i;
2391
2392
0
    for (i = 0; i < nmap; i++)
2393
0
  if (!strcmp ((char *)op, map[i].name))
2394
0
      return map[i].op;
2395
0
    return FcOpInvalid;
2396
0
}
2397
2398
static const FcOpMap fcCompareOps[] = {
2399
    { "eq",           FcOpEqual       },
2400
    { "not_eq",       FcOpNotEqual    },
2401
    { "less",         FcOpLess        },
2402
    { "less_eq",      FcOpLessEqual   },
2403
    { "more",         FcOpMore        },
2404
    { "more_eq",      FcOpMoreEqual   },
2405
    { "contains",     FcOpContains    },
2406
    { "not_contains", FcOpNotContains }
2407
};
2408
2409
0
#define NUM_COMPARE_OPS (int)(sizeof fcCompareOps / sizeof fcCompareOps[0])
2410
2411
static FcOp
2412
FcConfigLexCompare (const FcChar8 *compare)
2413
0
{
2414
0
    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2415
0
}
2416
2417
static void
2418
FcParseTest (FcConfigParse *parse)
2419
0
{
2420
0
    const FcChar8 *kind_string;
2421
0
    FcMatchKind    kind;
2422
0
    const FcChar8 *qual_string;
2423
0
    FcQual         qual;
2424
0
    const FcChar8 *name;
2425
0
    const FcChar8 *compare_string;
2426
0
    FcOp           compare;
2427
0
    FcExpr        *expr;
2428
0
    FcTest        *test;
2429
0
    const FcChar8 *iblanks_string;
2430
0
    int            flags = 0;
2431
2432
0
    kind_string = FcConfigGetAttribute (parse, "target");
2433
0
    if (!kind_string)
2434
0
  kind = FcMatchDefault;
2435
0
    else {
2436
0
  if (!strcmp ((char *)kind_string, "pattern"))
2437
0
      kind = FcMatchPattern;
2438
0
  else if (!strcmp ((char *)kind_string, "font"))
2439
0
      kind = FcMatchFont;
2440
0
  else if (!strcmp ((char *)kind_string, "scan"))
2441
0
      kind = FcMatchScan;
2442
0
  else if (!strcmp ((char *)kind_string, "default"))
2443
0
      kind = FcMatchDefault;
2444
0
  else {
2445
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2446
0
      return;
2447
0
  }
2448
0
    }
2449
0
    qual_string = FcConfigGetAttribute (parse, "qual");
2450
0
    if (!qual_string)
2451
0
  qual = FcQualAny;
2452
0
    else {
2453
0
  if (!strcmp ((char *)qual_string, "any"))
2454
0
      qual = FcQualAny;
2455
0
  else if (!strcmp ((char *)qual_string, "all"))
2456
0
      qual = FcQualAll;
2457
0
  else if (!strcmp ((char *)qual_string, "first"))
2458
0
      qual = FcQualFirst;
2459
0
  else if (!strcmp ((char *)qual_string, "not_first"))
2460
0
      qual = FcQualNotFirst;
2461
0
  else {
2462
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2463
0
      return;
2464
0
  }
2465
0
    }
2466
0
    name = FcConfigGetAttribute (parse, "name");
2467
0
    if (!name) {
2468
0
  FcConfigMessage (parse, FcSevereWarning, "missing test name");
2469
0
  return;
2470
0
    }
2471
0
    compare_string = FcConfigGetAttribute (parse, "compare");
2472
0
    if (!compare_string)
2473
0
  compare = FcOpEqual;
2474
0
    else {
2475
0
  compare = FcConfigLexCompare (compare_string);
2476
0
  if (compare == FcOpInvalid) {
2477
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2478
0
      return;
2479
0
  }
2480
0
    }
2481
0
    iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2482
0
    if (iblanks_string) {
2483
0
  FcBool f = FcFalse;
2484
2485
0
  if (!FcNameBool (iblanks_string, &f)) {
2486
0
      FcConfigMessage (parse,
2487
0
                       FcSevereWarning,
2488
0
                       "invalid test ignore-blanks \"%s\"", iblanks_string);
2489
0
  }
2490
0
  if (f)
2491
0
      flags |= FcOpFlagIgnoreBlanks;
2492
0
    }
2493
0
    expr = FcPopBinary (parse, FcOpComma);
2494
0
    if (!expr) {
2495
0
  FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2496
0
  return;
2497
0
    }
2498
0
    if (expr->op == FcOpComma) {
2499
0
  FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2500
0
    }
2501
0
    test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2502
0
    if (!test) {
2503
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2504
0
  return;
2505
0
    }
2506
0
    FcVStackPushTest (parse, test);
2507
0
}
2508
2509
static const FcOpMap fcModeOps[] = {
2510
    { "assign",         FcOpAssign        },
2511
    { "assign_replace", FcOpAssignReplace },
2512
    { "prepend",        FcOpPrepend       },
2513
    { "prepend_first",  FcOpPrependFirst  },
2514
    { "append",         FcOpAppend        },
2515
    { "append_last",    FcOpAppendLast    },
2516
    { "delete",         FcOpDelete        },
2517
    { "delete_all",     FcOpDeleteAll     },
2518
};
2519
2520
0
#define NUM_MODE_OPS (int)(sizeof fcModeOps / sizeof fcModeOps[0])
2521
2522
static FcOp
2523
FcConfigLexMode (const FcChar8 *mode)
2524
0
{
2525
0
    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2526
0
}
2527
2528
static void
2529
FcParseEdit (FcConfigParse *parse)
2530
0
{
2531
0
    const FcChar8 *name;
2532
0
    const FcChar8 *mode_string;
2533
0
    FcOp           mode;
2534
0
    FcValueBinding binding;
2535
0
    FcExpr        *expr;
2536
0
    FcEdit        *edit;
2537
2538
0
    name = FcConfigGetAttribute (parse, "name");
2539
0
    if (!name) {
2540
0
  FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2541
0
  return;
2542
0
    }
2543
0
    mode_string = FcConfigGetAttribute (parse, "mode");
2544
0
    if (!mode_string)
2545
0
  mode = FcOpAssign;
2546
0
    else {
2547
0
  mode = FcConfigLexMode (mode_string);
2548
0
  if (mode == FcOpInvalid) {
2549
0
      FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2550
0
      return;
2551
0
  }
2552
0
    }
2553
0
    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2554
0
  return;
2555
2556
0
    expr = FcPopBinary (parse, FcOpComma);
2557
0
    if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2558
0
        expr != NULL) {
2559
0
  FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2560
0
  FcExprDestroy (expr);
2561
0
  expr = NULL;
2562
0
    }
2563
0
    edit = FcEditCreate (parse, FcObjectFromName ((char *)name),
2564
0
                         mode, expr, binding);
2565
0
    if (!edit) {
2566
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2567
0
  FcExprDestroy (expr);
2568
0
  return;
2569
0
    }
2570
0
    if (!FcVStackPushEdit (parse, edit))
2571
0
  FcEditDestroy (edit);
2572
0
}
2573
2574
static void
2575
FcParseMatch (FcConfigParse *parse)
2576
0
{
2577
0
    const FcChar8 *kind_name;
2578
0
    FcMatchKind    kind;
2579
0
    FcVStack      *vstack;
2580
0
    FcRule        *rule = NULL, *r;
2581
0
    int            n;
2582
2583
0
    kind_name = FcConfigGetAttribute (parse, "target");
2584
0
    if (!kind_name)
2585
0
  kind = FcMatchPattern;
2586
0
    else {
2587
0
  if (!strcmp ((char *)kind_name, "pattern"))
2588
0
      kind = FcMatchPattern;
2589
0
  else if (!strcmp ((char *)kind_name, "font"))
2590
0
      kind = FcMatchFont;
2591
0
  else if (!strcmp ((char *)kind_name, "scan"))
2592
0
      kind = FcMatchScan;
2593
0
  else {
2594
0
      FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2595
0
      return;
2596
0
  }
2597
0
    }
2598
0
    while ((vstack = FcVStackPeek (parse))) {
2599
0
  switch ((int)vstack->tag) {
2600
0
  case FcVStackTest:
2601
0
      r = FcRuleCreate (FcRuleTest, vstack->u.test);
2602
0
      if (rule)
2603
0
    r->next = rule;
2604
0
      rule = r;
2605
0
      vstack->tag = FcVStackNone;
2606
0
      break;
2607
0
  case FcVStackEdit:
2608
0
      if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT) {
2609
0
    FcConfigMessage (parse, FcSevereError,
2610
0
                     "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2611
0
                     FcObjectName (vstack->u.edit->object));
2612
0
    if (rule)
2613
0
        FcRuleDestroy (rule);
2614
0
    return;
2615
0
      }
2616
0
      r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2617
0
      if (rule)
2618
0
    r->next = rule;
2619
0
      rule = r;
2620
0
      vstack->tag = FcVStackNone;
2621
0
      break;
2622
0
  default:
2623
0
      FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2624
0
      break;
2625
0
  }
2626
0
  FcVStackPopAndDestroy (parse);
2627
0
    }
2628
0
    if (!rule) {
2629
0
  FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2630
0
  return;
2631
0
    }
2632
0
    if ((n = FcRuleSetAdd (parse->ruleset, rule, kind)) == -1) {
2633
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2634
0
  FcRuleDestroy (rule);
2635
0
    } else if (parse->config->maxObjects < n)
2636
0
  parse->config->maxObjects = n;
2637
0
}
2638
2639
static void
2640
FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2641
0
{
2642
0
    FcVStack *vstack;
2643
2644
0
    while ((vstack = FcVStackPeek (parse))) {
2645
0
  switch ((int)vstack->tag) {
2646
0
  case FcVStackGlob:
2647
0
      if (!parse->scanOnly && !FcConfigGlobAdd (parse->config,
2648
0
                                                vstack->u.string,
2649
0
                                                element == FcElementAcceptfont)) {
2650
0
    if (FcStrUsesHome (vstack->u.string) && FcConfigHome() == NULL)
2651
0
        FcConfigMessage (parse, FcSevereWarning, "Home is disabled");
2652
0
    else
2653
0
        FcConfigMessage (parse, FcSevereError, "out of memory");
2654
0
      } else {
2655
0
    if (parse->scanOnly && vstack->u.string) {
2656
0
        FcStrFree (vstack->u.string);
2657
0
        vstack->tag = FcVStackNone;
2658
0
    }
2659
0
      }
2660
0
      break;
2661
0
  case FcVStackPattern:
2662
0
      if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
2663
0
                                                    vstack->u.pattern,
2664
0
                                                    element == FcElementAcceptfont)) {
2665
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
2666
0
      } else {
2667
0
    if (parse->scanOnly && vstack->u.pattern)
2668
0
        FcPatternDestroy (vstack->u.pattern);
2669
0
    vstack->tag = FcVStackNone;
2670
0
      }
2671
0
      break;
2672
0
  default:
2673
0
      FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2674
0
      break;
2675
0
  }
2676
0
  FcVStackPopAndDestroy (parse);
2677
0
    }
2678
0
}
2679
2680
static FcValue
2681
FcPopValue (FcConfigParse *parse)
2682
0
{
2683
0
    FcVStack *vstack = FcVStackPeek (parse);
2684
0
    FcValue   value;
2685
2686
0
    value.type = FcTypeVoid;
2687
2688
0
    if (!vstack)
2689
0
  return value;
2690
2691
0
    switch ((int)vstack->tag) {
2692
0
    case FcVStackString:
2693
0
  value.u.s = FcStrdup (vstack->u.string);
2694
0
  if (value.u.s)
2695
0
      value.type = FcTypeString;
2696
0
  break;
2697
0
    case FcVStackConstant:
2698
0
  if (FcNameConstant (vstack->u.string, &value.u.i))
2699
0
      value.type = FcTypeInteger;
2700
0
  break;
2701
0
    case FcVStackInteger:
2702
0
  value.u.i = vstack->u.integer;
2703
0
  value.type = FcTypeInteger;
2704
0
  break;
2705
0
    case FcVStackDouble:
2706
0
  value.u.d = vstack->u._double;
2707
0
  value.type = FcTypeDouble;
2708
0
  break;
2709
0
    case FcVStackBool:
2710
0
  value.u.b = vstack->u.bool_;
2711
0
  value.type = FcTypeBool;
2712
0
  break;
2713
0
    case FcVStackCharSet:
2714
0
  value.u.c = FcCharSetCopy (vstack->u.charset);
2715
0
  if (value.u.c)
2716
0
      value.type = FcTypeCharSet;
2717
0
  break;
2718
0
    case FcVStackLangSet:
2719
0
  value.u.l = FcLangSetCopy (vstack->u.langset);
2720
0
  if (value.u.l)
2721
0
      value.type = FcTypeLangSet;
2722
0
  break;
2723
0
    case FcVStackRange:
2724
0
  value.u.r = FcRangeCopy (vstack->u.range);
2725
0
  if (value.u.r)
2726
0
      value.type = FcTypeRange;
2727
0
  break;
2728
0
    default:
2729
0
  FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2730
0
                   vstack->tag);
2731
0
  break;
2732
0
    }
2733
0
    FcVStackPopAndDestroy (parse);
2734
2735
0
    return value;
2736
0
}
2737
2738
static void
2739
FcParsePatelt (FcConfigParse *parse)
2740
0
{
2741
0
    FcValue     value;
2742
0
    FcPattern  *pattern = FcPatternCreate();
2743
0
    const char *name;
2744
2745
0
    if (!pattern) {
2746
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2747
0
  return;
2748
0
    }
2749
2750
0
    name = (char *)FcConfigGetAttribute (parse, "name");
2751
0
    if (!name) {
2752
0
  FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2753
0
  FcPatternDestroy (pattern);
2754
0
  return;
2755
0
    }
2756
2757
0
    for (;;) {
2758
0
  value = FcPopValue (parse);
2759
0
  if (value.type == FcTypeVoid)
2760
0
      break;
2761
0
  if (!FcPatternAdd (pattern, name, value, FcTrue)) {
2762
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2763
0
      FcValueDestroy (value);
2764
0
      break;
2765
0
  }
2766
0
  FcValueDestroy (value);
2767
0
    }
2768
2769
0
    FcVStackPushPattern (parse, pattern);
2770
0
}
2771
2772
static void
2773
FcParsePattern (FcConfigParse *parse)
2774
0
{
2775
0
    FcVStack  *vstack;
2776
0
    FcPattern *pattern = FcPatternCreate();
2777
2778
0
    if (!pattern) {
2779
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2780
0
  return;
2781
0
    }
2782
2783
0
    while ((vstack = FcVStackPeek (parse))) {
2784
0
  switch ((int)vstack->tag) {
2785
0
  case FcVStackPattern:
2786
0
      if (!FcPatternAppend (pattern, vstack->u.pattern)) {
2787
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
2788
0
    FcPatternDestroy (pattern);
2789
0
    return;
2790
0
      }
2791
0
      break;
2792
0
  default:
2793
0
      FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2794
0
      break;
2795
0
  }
2796
0
  FcVStackPopAndDestroy (parse);
2797
0
    }
2798
2799
0
    FcVStackPushPattern (parse, pattern);
2800
0
}
2801
2802
static void
2803
FcEndElement (void *userData, const XML_Char *name FC_UNUSED)
2804
318
{
2805
318
    FcConfigParse *parse = userData;
2806
318
    FcChar8       *data;
2807
2808
318
    if (!parse->pstack)
2809
0
  return;
2810
318
    switch (parse->pstack->element) {
2811
0
    case FcElementNone:
2812
0
  break;
2813
106
    case FcElementFontconfig:
2814
106
  break;
2815
106
    case FcElementDir:
2816
106
  FcParseDir (parse);
2817
106
  break;
2818
106
    case FcElementCacheDir:
2819
106
  FcParseCacheDir (parse);
2820
106
  break;
2821
0
    case FcElementCache:
2822
0
  data = FcStrBufDoneStatic (&parse->pstack->str);
2823
0
  if (!data) {
2824
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2825
0
      break;
2826
0
  }
2827
  /* discard this data; no longer used */
2828
0
  FcStrBufDestroy (&parse->pstack->str);
2829
0
  break;
2830
0
    case FcElementInclude:
2831
0
  FcParseInclude (parse);
2832
0
  break;
2833
0
    case FcElementConfig:
2834
0
  break;
2835
0
    case FcElementMatch:
2836
0
  FcParseMatch (parse);
2837
0
  break;
2838
0
    case FcElementAlias:
2839
0
  FcParseAlias (parse);
2840
0
  break;
2841
0
    case FcElementDescription:
2842
0
  FcParseDescription (parse);
2843
0
  break;
2844
0
    case FcElementRemapDir:
2845
0
  FcParseRemapDir (parse);
2846
0
  break;
2847
0
    case FcElementResetDirs:
2848
0
  FcParseResetDirs (parse);
2849
0
  break;
2850
2851
0
    case FcElementRescan:
2852
0
  FcParseRescan (parse);
2853
0
  break;
2854
2855
0
    case FcElementPrefer:
2856
0
  FcParseFamilies (parse, FcVStackPrefer);
2857
0
  break;
2858
0
    case FcElementAccept:
2859
0
  FcParseFamilies (parse, FcVStackAccept);
2860
0
  break;
2861
0
    case FcElementDefault:
2862
0
  FcParseFamilies (parse, FcVStackDefault);
2863
0
  break;
2864
0
    case FcElementFamily:
2865
0
  FcParseFamily (parse);
2866
0
  break;
2867
2868
0
    case FcElementTest:
2869
0
  FcParseTest (parse);
2870
0
  break;
2871
0
    case FcElementEdit:
2872
0
  FcParseEdit (parse);
2873
0
  break;
2874
2875
0
    case FcElementInt:
2876
0
  FcParseInt (parse);
2877
0
  break;
2878
0
    case FcElementDouble:
2879
0
  FcParseDouble (parse);
2880
0
  break;
2881
0
    case FcElementString:
2882
0
  FcParseString (parse, FcVStackString);
2883
0
  break;
2884
0
    case FcElementMatrix:
2885
0
  FcParseMatrix (parse);
2886
0
  break;
2887
0
    case FcElementRange:
2888
0
  FcParseRange (parse);
2889
0
  break;
2890
0
    case FcElementBool:
2891
0
  FcParseBool (parse);
2892
0
  break;
2893
0
    case FcElementCharSet:
2894
0
  FcParseCharSet (parse);
2895
0
  break;
2896
0
    case FcElementLangSet:
2897
0
  FcParseLangSet (parse);
2898
0
  break;
2899
0
    case FcElementSelectfont:
2900
0
  break;
2901
0
    case FcElementAcceptfont:
2902
0
    case FcElementRejectfont:
2903
0
  FcParseAcceptRejectFont (parse, parse->pstack->element);
2904
0
  break;
2905
0
    case FcElementGlob:
2906
0
  FcParseString (parse, FcVStackGlob);
2907
0
  break;
2908
0
    case FcElementPattern:
2909
0
  FcParsePattern (parse);
2910
0
  break;
2911
0
    case FcElementPatelt:
2912
0
  FcParsePatelt (parse);
2913
0
  break;
2914
0
    case FcElementName:
2915
0
  FcParseName (parse);
2916
0
  break;
2917
0
    case FcElementConst:
2918
0
  FcParseString (parse, FcVStackConstant);
2919
0
  break;
2920
0
    case FcElementOr:
2921
0
  FcParseBinary (parse, FcOpOr);
2922
0
  break;
2923
0
    case FcElementAnd:
2924
0
  FcParseBinary (parse, FcOpAnd);
2925
0
  break;
2926
0
    case FcElementEq:
2927
0
  FcParseBinary (parse, FcOpEqual);
2928
0
  break;
2929
0
    case FcElementNotEq:
2930
0
  FcParseBinary (parse, FcOpNotEqual);
2931
0
  break;
2932
0
    case FcElementLess:
2933
0
  FcParseBinary (parse, FcOpLess);
2934
0
  break;
2935
0
    case FcElementLessEq:
2936
0
  FcParseBinary (parse, FcOpLessEqual);
2937
0
  break;
2938
0
    case FcElementMore:
2939
0
  FcParseBinary (parse, FcOpMore);
2940
0
  break;
2941
0
    case FcElementMoreEq:
2942
0
  FcParseBinary (parse, FcOpMoreEqual);
2943
0
  break;
2944
0
    case FcElementContains:
2945
0
  FcParseBinary (parse, FcOpContains);
2946
0
  break;
2947
0
    case FcElementNotContains:
2948
0
  FcParseBinary (parse, FcOpNotContains);
2949
0
  break;
2950
0
    case FcElementPlus:
2951
0
  FcParseBinary (parse, FcOpPlus);
2952
0
  break;
2953
0
    case FcElementMinus:
2954
0
  FcParseBinary (parse, FcOpMinus);
2955
0
  break;
2956
0
    case FcElementTimes:
2957
0
  FcParseBinary (parse, FcOpTimes);
2958
0
  break;
2959
0
    case FcElementDivide:
2960
0
  FcParseBinary (parse, FcOpDivide);
2961
0
  break;
2962
0
    case FcElementNot:
2963
0
  FcParseUnary (parse, FcOpNot);
2964
0
  break;
2965
0
    case FcElementIf:
2966
0
  FcParseBinary (parse, FcOpQuest);
2967
0
  break;
2968
0
    case FcElementFloor:
2969
0
  FcParseUnary (parse, FcOpFloor);
2970
0
  break;
2971
0
    case FcElementCeil:
2972
0
  FcParseUnary (parse, FcOpCeil);
2973
0
  break;
2974
0
    case FcElementRound:
2975
0
  FcParseUnary (parse, FcOpRound);
2976
0
  break;
2977
0
    case FcElementTrunc:
2978
0
  FcParseUnary (parse, FcOpTrunc);
2979
0
  break;
2980
0
    case FcElementUnknown:
2981
0
  break;
2982
318
    }
2983
318
    (void)FcPStackPop (parse);
2984
318
}
2985
2986
static void
2987
FcCharacterData (void *userData, const XML_Char *s, int len)
2988
212
{
2989
212
    FcConfigParse *parse = userData;
2990
2991
212
    if (!parse->pstack)
2992
0
  return;
2993
212
    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *)s, len))
2994
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2995
212
}
2996
2997
static void
2998
FcStartDoctypeDecl (void           *userData,
2999
                    const XML_Char *doctypeName,
3000
                    const XML_Char *sysid FC_UNUSED,
3001
                    const XML_Char *pubid FC_UNUSED,
3002
                    int             has_internal_subset FC_UNUSED)
3003
0
{
3004
0
    FcConfigParse *parse = userData;
3005
3006
0
    if (strcmp ((char *)doctypeName, "fontconfig") != 0)
3007
0
  FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
3008
0
}
3009
3010
#ifdef ENABLE_LIBXML2
3011
3012
static void
3013
FcInternalSubsetDecl (void           *userData,
3014
                      const XML_Char *doctypeName,
3015
                      const XML_Char *sysid,
3016
                      const XML_Char *pubid)
3017
{
3018
    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3019
}
3020
3021
static void
3022
FcExternalSubsetDecl (void           *userData,
3023
                      const XML_Char *doctypeName,
3024
                      const XML_Char *sysid,
3025
                      const XML_Char *pubid)
3026
{
3027
    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3028
}
3029
3030
#else /* ENABLE_LIBXML2 */
3031
3032
static void
3033
FcEndDoctypeDecl (void *userData FC_UNUSED)
3034
0
{
3035
0
}
3036
3037
#endif /* ENABLE_LIBXML2 */
3038
3039
static int
3040
FcSortCmpStr (const void *a, const void *b)
3041
0
{
3042
0
    const FcChar8 *as = *((FcChar8 **)a);
3043
0
    const FcChar8 *bs = *((FcChar8 **)b);
3044
0
    return FcStrCmp (as, bs);
3045
0
}
3046
3047
static FcBool
3048
FcConfigParseAndLoadDir (FcConfig      *config,
3049
                         const FcChar8 *name,
3050
                         const FcChar8 *dir,
3051
                         FcBool         complain,
3052
                         FcBool         load)
3053
0
{
3054
0
    DIR           *d;
3055
0
    struct dirent *e;
3056
0
    FcBool         ret = FcTrue;
3057
0
    FcChar8       *file;
3058
0
    FcChar8       *base;
3059
0
    FcStrSet      *files;
3060
3061
0
    d = opendir ((char *)dir);
3062
0
    if (!d) {
3063
0
  if (complain)
3064
0
      FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3065
0
                       name);
3066
0
  ret = FcFalse;
3067
0
  goto bail0;
3068
0
    }
3069
    /* freed below */
3070
0
    file = (FcChar8 *)malloc (strlen ((char *)dir) + 1 + FC_MAX_FILE_LEN + 1);
3071
0
    if (!file) {
3072
0
  ret = FcFalse;
3073
0
  goto bail1;
3074
0
    }
3075
3076
0
    strcpy ((char *)file, (char *)dir);
3077
0
    strcat ((char *)file, "/");
3078
0
    base = file + strlen ((char *)file);
3079
3080
0
    files = FcStrSetCreateEx (FCSS_GROW_BY_64);
3081
0
    if (!files) {
3082
0
  ret = FcFalse;
3083
0
  goto bail2;
3084
0
    }
3085
3086
0
    if (FcDebug() & FC_DBG_CONFIG)
3087
0
  printf ("\tScanning config dir %s\n", dir);
3088
3089
0
    if (load)
3090
0
  FcConfigAddConfigDir (config, dir);
3091
3092
0
    while (ret && (e = readdir (d))) {
3093
0
  int d_len;
3094
0
#define TAIL     ".conf"
3095
0
#define TAIL_LEN 5
3096
  /*
3097
   * Add all files of the form [0-9]*.conf
3098
   */
3099
0
  d_len = strlen (e->d_name);
3100
0
  if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3101
0
      d_len > TAIL_LEN &&
3102
0
      strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) {
3103
0
      strcpy ((char *)base, (char *)e->d_name);
3104
0
      if (!FcStrSetAdd (files, file)) {
3105
0
    ret = FcFalse;
3106
0
    goto bail3;
3107
0
      }
3108
0
  }
3109
0
    }
3110
0
    if (ret) {
3111
0
  int i;
3112
0
  qsort (files->strs, files->num, sizeof (FcChar8 *),
3113
0
         (int (*) (const void *, const void *))FcSortCmpStr);
3114
0
  for (i = 0; ret && i < files->num; i++)
3115
0
      ret = _FcConfigParse (config, files->strs[i], complain, load);
3116
0
    }
3117
0
bail3:
3118
0
    FcStrSetDestroy (files);
3119
0
bail2:
3120
0
    free (file);
3121
0
bail1:
3122
0
    closedir (d);
3123
0
bail0:
3124
0
    return ret || !complain;
3125
0
}
3126
3127
static FcBool
3128
FcConfigParseAndLoadFromMemoryInternal (FcConfig      *config,
3129
                                        const FcChar8 *filename,
3130
                                        const FcChar8 *buffer,
3131
                                        FcBool         complain,
3132
                                        FcBool         load)
3133
106
{
3134
106
    XML_Parser    p;
3135
106
    size_t        len;
3136
106
    FcConfigParse parse;
3137
106
    FcBool        error = FcTrue;
3138
106
    FcMatchKind   k;
3139
106
    FcPtrListIter liter;
3140
3141
#ifdef ENABLE_LIBXML2
3142
    xmlSAXHandler sax;
3143
#else
3144
106
    void          *buf;
3145
106
    const FcChar8 *s;
3146
106
    size_t         buflen;
3147
106
#endif
3148
3149
106
    FcInitDebug();
3150
3151
106
    if (!buffer)
3152
0
  return FcFalse;
3153
106
    len = strlen ((const char *)buffer);
3154
106
    if (FcDebug() & FC_DBG_CONFIG)
3155
0
  printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
3156
3157
#ifdef ENABLE_LIBXML2
3158
    memset (&sax, 0, sizeof (sax));
3159
3160
    sax.internalSubset = FcInternalSubsetDecl;
3161
    sax.externalSubset = FcExternalSubsetDecl;
3162
    sax.startElement = FcStartElement;
3163
    sax.endElement = FcEndElement;
3164
    sax.characters = FcCharacterData;
3165
3166
    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *)filename);
3167
#else
3168
106
    p = XML_ParserCreate ("UTF-8");
3169
106
#endif
3170
3171
106
    if (!p)
3172
0
  goto bail1;
3173
3174
106
    if (!FcConfigParseInit (&parse, filename, config, p, load))
3175
0
  goto bail2;
3176
3177
106
#ifndef ENABLE_LIBXML2
3178
3179
106
    XML_SetUserData (p, &parse);
3180
3181
106
    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3182
106
    XML_SetElementHandler (p, FcStartElement, FcEndElement);
3183
106
    XML_SetCharacterDataHandler (p, FcCharacterData);
3184
3185
106
#endif /* ENABLE_LIBXML2 */
3186
3187
106
#ifndef ENABLE_LIBXML2
3188
106
    s = buffer;
3189
212
    do {
3190
212
  buf = XML_GetBuffer (p, BUFSIZ);
3191
212
  if (!buf) {
3192
0
      FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3193
0
      goto bail3;
3194
0
  }
3195
212
  if (len > BUFSIZ) {
3196
0
      buflen = BUFSIZ;
3197
0
      len -= BUFSIZ;
3198
212
  } else {
3199
212
      buflen = len;
3200
212
      len = 0;
3201
212
  }
3202
212
  memcpy (buf, s, buflen);
3203
212
  s = s + buflen;
3204
212
#endif
3205
3206
#ifdef ENABLE_LIBXML2
3207
  if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
3208
#else
3209
212
    if (!XML_ParseBuffer (p, buflen, buflen == 0))
3210
0
#endif
3211
0
  {
3212
0
      FcConfigMessage (&parse, FcSevereError, "%s",
3213
0
                       XML_ErrorString (XML_GetErrorCode (p)));
3214
0
      goto bail3;
3215
0
  }
3216
212
#ifndef ENABLE_LIBXML2
3217
212
    } while (buflen != 0);
3218
106
#endif
3219
106
    error = parse.error;
3220
106
    if (load) {
3221
424
  for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) {
3222
318
      FcPtrListIter iter;
3223
3224
318
      FcPtrListIterInit (parse.ruleset->subst[k], &iter);
3225
318
      if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter)) {
3226
0
    FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
3227
0
    FcRuleSetReference (parse.ruleset);
3228
0
    FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
3229
0
      }
3230
318
  }
3231
106
    }
3232
106
    FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
3233
106
    FcRuleSetReference (parse.ruleset);
3234
106
    FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
3235
106
bail3:
3236
106
    FcConfigCleanup (&parse);
3237
106
bail2:
3238
106
    XML_ParserFree (p);
3239
106
bail1:
3240
106
    if (error && complain) {
3241
0
  FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
3242
0
  return FcFalse;
3243
0
    }
3244
106
    if (FcDebug() & FC_DBG_CONFIG)
3245
0
  printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
3246
106
    return FcTrue;
3247
106
}
3248
3249
static FcBool
3250
_FcConfigParse (FcConfig      *config,
3251
                const FcChar8 *name,
3252
                FcBool         complain,
3253
                FcBool         load)
3254
212
{
3255
212
    FcChar8 *filename = NULL, *realfilename = NULL;
3256
212
    int      fd;
3257
212
    int      len;
3258
212
    FcStrBuf sbuf;
3259
212
    char     buf[BUFSIZ];
3260
212
    FcBool   ret = FcFalse, complain_again = complain;
3261
212
    FcStrBuf reason;
3262
3263
212
    FcStrBufInit (&reason, NULL, 0);
3264
#ifdef _WIN32
3265
    _ensureWin32GettersReady();
3266
#endif
3267
3268
212
    filename = FcConfigGetFilename (config, name);
3269
212
    if (!filename) {
3270
106
  FcStrBufString (&reason, (FcChar8 *)"No such file: ");
3271
106
  FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3272
106
  goto bail0;
3273
106
    }
3274
106
    realfilename = FcConfigRealFilename (config, name);
3275
106
    if (!realfilename) {
3276
0
  FcStrBufString (&reason, (FcChar8 *)"No such realfile: ");
3277
0
  FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3278
0
  goto bail0;
3279
0
    }
3280
106
    if (FcStrSetMember (config->availConfigFiles, realfilename)) {
3281
0
  FcStrFree (filename);
3282
0
  FcStrFree (realfilename);
3283
0
  return FcTrue;
3284
0
    }
3285
3286
106
    if (load) {
3287
106
  if (!FcStrSetAdd (config->configFiles, filename))
3288
0
      goto bail0;
3289
106
    }
3290
106
    if (!FcStrSetAdd (config->availConfigFiles, realfilename))
3291
0
  goto bail0;
3292
3293
106
    if (FcFileIsDir (realfilename)) {
3294
0
  ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
3295
0
  FcStrFree (filename);
3296
0
  FcStrFree (realfilename);
3297
0
  return ret;
3298
0
    }
3299
3300
106
    FcStrBufInit (&sbuf, NULL, 0);
3301
3302
106
    fd = FcOpen ((char *)realfilename, O_RDONLY);
3303
106
    if (fd == -1) {
3304
0
  FcStrBufString (&reason, (FcChar8 *)"Unable to open ");
3305
0
  FcStrBufString (&reason, realfilename);
3306
0
  goto bail1;
3307
0
    }
3308
3309
212
    do {
3310
212
  len = read (fd, buf, BUFSIZ);
3311
212
  if (len < 0) {
3312
0
      int  errno_ = errno;
3313
0
      char ebuf[BUFSIZ + 1];
3314
3315
0
#if HAVE_STRERROR_R
3316
0
      strerror_r (errno_, ebuf, BUFSIZ);
3317
#elif HAVE_STRERROR
3318
      char  *tmp = strerror (errno_);
3319
      size_t len = strlen (tmp);
3320
      memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
3321
      ebuf[FC_MIN (BUFSIZ, len)] = 0;
3322
#else
3323
      ebuf[0] = 0;
3324
#endif
3325
0
      FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
3326
0
      close (fd);
3327
0
      goto bail1;
3328
0
  }
3329
212
  FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
3330
212
    } while (len != 0);
3331
106
    close (fd);
3332
3333
106
    ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
3334
106
    complain_again = FcFalse; /* no need to reclaim here */
3335
106
bail1:
3336
106
    FcStrBufDestroy (&sbuf);
3337
212
bail0:
3338
212
    if (filename)
3339
106
  FcStrFree (filename);
3340
212
    if (realfilename)
3341
106
  FcStrFree (realfilename);
3342
212
    if (!complain) {
3343
106
  FcStrBufDestroy (&reason);
3344
106
  return FcTrue;
3345
106
    }
3346
106
    if (!ret && complain_again) {
3347
0
  if (name)
3348
0
      FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason));
3349
0
  else
3350
0
      FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason));
3351
0
  FcStrBufDestroy (&reason);
3352
0
  return FcFalse;
3353
0
    }
3354
106
    FcStrBufDestroy (&reason);
3355
106
    return ret;
3356
106
}
3357
3358
FcBool
3359
FcConfigParseOnly (FcConfig      *config,
3360
                   const FcChar8 *name,
3361
                   FcBool         complain)
3362
106
{
3363
106
    return _FcConfigParse (config, name, complain, FcFalse);
3364
106
}
3365
3366
FcBool
3367
FcConfigParseAndLoad (FcConfig      *config,
3368
                      const FcChar8 *name,
3369
                      FcBool         complain)
3370
106
{
3371
106
    return _FcConfigParse (config, name, complain, FcTrue);
3372
106
}
3373
3374
FcBool
3375
FcConfigParseAndLoadFromMemory (FcConfig      *config,
3376
                                const FcChar8 *buffer,
3377
                                FcBool         complain)
3378
0
{
3379
0
    return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
3380
0
}
3381
3382
#ifdef _WIN32
3383
static void
3384
_ensureWin32GettersReady ()
3385
{
3386
    if (!pGetSystemWindowsDirectory) {
3387
  HMODULE hk32 = GetModuleHandleA ("kernel32.dll");
3388
  if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetProcAddress (hk32, "GetSystemWindowsDirectoryA")))
3389
      pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetWindowsDirectory;
3390
    }
3391
    if (!pSHGetFolderPathA) {
3392
  HMODULE hSh = LoadLibraryA ("shfolder.dll");
3393
  /* the check is done later, because there is no provided fallback */
3394
  if (hSh)
3395
      pSHGetFolderPathA = (pfnSHGetFolderPathA)GetProcAddress (hSh, "SHGetFolderPathA");
3396
    }
3397
}
3398
#endif  // _WIN32
3399
3400
#define __fcxml__
3401
#include "fcaliastail.h"
3402
#undef __fcxml__