Coverage Report

Created: 2026-06-30 11:14

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