Coverage Report

Created: 2026-08-14 10:22

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
624
#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
312
{
489
312
    int i;
490
624
    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
491
624
  if (!strcmp ((char *)name, fcElementMap[i].name))
492
312
      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
312
{
1051
312
    FcVStack *vstack = parse->vstack;
1052
1053
312
    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
1054
312
}
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
312
{
1122
312
    while (FcVStackPeek (parse))
1123
0
  FcVStackPopAndDestroy (parse);
1124
312
}
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
312
{
1141
312
    int       slen;
1142
312
    int       i;
1143
312
    FcChar8 **newp;
1144
312
    FcChar8  *s;
1145
1146
312
    if (!attr)
1147
0
  return 0;
1148
312
    slen = 0;
1149
312
    for (i = 0; attr[i]; i++)
1150
0
  slen += strlen ((char *)attr[i]) + 1;
1151
312
    if (i == 0)
1152
312
  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
312
{
1176
312
    FcPStack *newp;
1177
1178
312
    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1179
312
  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
312
    newp->prev = parse->pstack;
1187
312
    newp->element = element;
1188
312
    newp->attr = FcConfigSaveAttr (attr, newp->attr_buf_static, sizeof (newp->attr_buf_static));
1189
312
    FcStrBufInit (&newp->str, 0, 0);
1190
312
    parse->pstack = newp;
1191
312
    return FcTrue;
1192
312
}
1193
1194
static FcBool
1195
FcPStackPop (FcConfigParse *parse)
1196
312
{
1197
312
    FcPStack     *old;
1198
312
    static FcBool retrieved = FcFalse;
1199
312
    const char   *env = NULL;
1200
1201
312
    if (!parse->pstack) {
1202
0
  FcConfigMessage (parse, FcSevereError, "mismatching element");
1203
0
  return FcFalse;
1204
0
    }
1205
1206
    /* Don't check the attributes for FcElementNone */
1207
312
    if (parse->pstack->element != FcElementNone &&
1208
312
        parse->pstack->attr) {
1209
0
  if (!retrieved) {
1210
0
      FcBool flag = FcFalse;
1211
1212
0
      env = getenv ("FONTCONFIG_WARN_INVALID_ATTRS");
1213
0
      if (env && FcNameBool ((const FcChar8 *)env, &flag)) {
1214
0
    retrieved = FcTrue;
1215
0
    FcConfigSetWarningFlags (parse->config, FC_WARN_INVALID_ATTR, flag);
1216
0
      }
1217
0
  }
1218
  /* Warn only when a flag is turned on */
1219
0
  if (FcConfigGetWarningFlags (parse->config) & FC_WARN_INVALID_ATTR) {
1220
      /* Warn about unused attrs. */
1221
0
      FcChar8 **attrs = parse->pstack->attr;
1222
0
      while (*attrs) {
1223
0
    if (attrs[0][0]) {
1224
0
        FcConfigMessage (parse, FcSevereWarning, "invalid attribute '%s'", attrs[0]);
1225
0
    }
1226
0
    attrs += 2;
1227
0
      }
1228
0
  }
1229
0
    }
1230
1231
312
    FcVStackClear (parse);
1232
312
    old = parse->pstack;
1233
312
    parse->pstack = old->prev;
1234
312
    FcStrBufDestroy (&old->str);
1235
1236
312
    if (old->attr && old->attr != old->attr_buf_static)
1237
0
  free (old->attr);
1238
1239
312
    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1240
312
  parse->pstack_static_used--;
1241
0
    else
1242
0
  free (old);
1243
312
    return FcTrue;
1244
312
}
1245
1246
static FcBool
1247
FcConfigParseInit (FcConfigParse *parse,
1248
                   const FcChar8 *name,
1249
                   FcConfig      *config,
1250
                   XML_Parser     parser,
1251
                   FcBool         enabled)
1252
104
{
1253
104
    parse->pstack = 0;
1254
104
    parse->pstack_static_used = 0;
1255
104
    parse->vstack = 0;
1256
104
    parse->vstack_static_used = 0;
1257
104
    parse->error = FcFalse;
1258
104
    parse->name = name;
1259
104
    parse->config = config;
1260
104
    parse->ruleset = FcRuleSetCreate (name);
1261
104
    parse->parser = parser;
1262
104
    parse->scanOnly = !enabled;
1263
104
    FcRuleSetEnable (parse->ruleset, enabled);
1264
1265
104
    return FcTrue;
1266
104
}
1267
1268
static void
1269
FcConfigCleanup (FcConfigParse *parse)
1270
104
{
1271
104
    while (parse->pstack)
1272
0
  FcPStackPop (parse);
1273
104
    FcRuleSetDestroy (parse->ruleset);
1274
104
    parse->ruleset = NULL;
1275
104
}
1276
1277
static const FcChar8 *
1278
FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1279
312
{
1280
312
    FcChar8 **attrs;
1281
312
    if (!parse->pstack)
1282
0
  return 0;
1283
1284
312
    attrs = parse->pstack->attr;
1285
312
    if (!attrs)
1286
312
  return 0;
1287
1288
0
    while (*attrs) {
1289
0
  if (!strcmp ((char *)*attrs, attr)) {
1290
0
      attrs[0][0] = '\0'; /* Mark as used. */
1291
0
      return attrs[1];
1292
0
  }
1293
0
  attrs += 2;
1294
0
    }
1295
0
    return 0;
1296
0
}
1297
1298
static FcStrSet *
1299
_get_real_paths_from_prefix (FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix)
1300
104
{
1301
#ifdef _WIN32
1302
    FcChar8 buffer[1000] = { 0 };
1303
#endif
1304
104
    FcChar8  *parent = NULL, *retval = NULL;
1305
104
    FcStrSet *e = NULL;
1306
1307
104
    if (prefix) {
1308
0
  if (FcStrCmp (prefix, (const FcChar8 *)"xdg") == 0) {
1309
0
      parent = FcConfigXdgDataHome();
1310
0
      if (!parent) {
1311
    /* Home directory might be disabled */
1312
0
    return NULL;
1313
0
      }
1314
0
      e = FcConfigXdgDataDirs();
1315
0
      if (!e) {
1316
0
    FcStrFree (parent);
1317
0
    return NULL;
1318
0
      }
1319
0
  } else if (FcStrCmp (prefix, (const FcChar8 *)"default") == 0 ||
1320
0
             FcStrCmp (prefix, (const FcChar8 *)"cwd") == 0) {
1321
      /* Nothing to do */
1322
0
  } else if (FcStrCmp (prefix, (const FcChar8 *)"relative") == 0) {
1323
0
      FcChar8 *p = FcStrRealPath (parse->name);
1324
1325
0
      if (!p)
1326
0
    return NULL;
1327
0
      parent = FcStrDirname (p);
1328
0
      FcStrFree (p);
1329
0
      if (!parent)
1330
0
    return NULL;
1331
0
  }
1332
0
    }
1333
104
#ifndef _WIN32
1334
    /* For Win32, check this later for dealing with special cases */
1335
104
    else {
1336
104
  if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1337
0
      FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1338
104
    }
1339
#else
1340
    if (strcmp ((const char *)path, "CUSTOMFONTDIR") == 0) {
1341
  FcChar8 *p;
1342
  path = buffer;
1343
  if (!GetModuleFileName (NULL, (LPCH)buffer, sizeof (buffer) - 20)) {
1344
      FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1345
      return NULL;
1346
  }
1347
  /*
1348
   * Must use the multi-byte aware function to search
1349
   * for backslash because East Asian double-byte code
1350
   * pages have characters with backslash as the second
1351
   * byte.
1352
   */
1353
  p = _mbsrchr (path, '\\');
1354
  if (p)
1355
      *p = '\0';
1356
  strcat ((char *)path, "\\fonts");
1357
    } else if (strcmp ((const char *)path, "APPSHAREFONTDIR") == 0) {
1358
  FcChar8 *p;
1359
  path = buffer;
1360
  if (!GetModuleFileName (NULL, (LPCH)buffer, sizeof (buffer) - 20)) {
1361
      FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1362
      return NULL;
1363
  }
1364
  p = _mbsrchr (path, '\\');
1365
  if (p)
1366
      *p = '\0';
1367
  strcat ((char *)path, "\\..\\share\\fonts");
1368
    } else if (strcmp ((const char *)path, "WINDOWSUSERFONTDIR") == 0) {
1369
  path = buffer;
1370
  if (!(pSHGetFolderPathA && SUCCEEDED (pSHGetFolderPathA (NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, (char *)buffer)))) {
1371
      FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
1372
      return NULL;
1373
  }
1374
  strcat ((char *)path, "\\Microsoft\\Windows\\Fonts");
1375
    } else if (strcmp ((const char *)path, "WINDOWSFONTDIR") == 0) {
1376
  int rc;
1377
  path = buffer;
1378
  _ensureWin32GettersReady();
1379
  rc = pGetSystemWindowsDirectory ((LPSTR)buffer, sizeof (buffer) - 20);
1380
  if (rc == 0 || rc > sizeof (buffer) - 20) {
1381
      FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
1382
      return NULL;
1383
  }
1384
  if (path[strlen ((const char *)path) - 1] != '\\')
1385
      strcat ((char *)path, "\\");
1386
  strcat ((char *)path, "fonts");
1387
    } else {
1388
  if (!prefix) {
1389
      if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1390
    FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1391
  }
1392
    }
1393
#endif
1394
104
    if (parent) {
1395
0
  retval = FcStrBuildFilename (parent, path, NULL);
1396
0
  FcStrFree (parent);
1397
104
    } else {
1398
104
  retval = FcStrCopy (path);
1399
104
    }
1400
104
    if (!e)
1401
104
  e = FcStrSetCreate();
1402
0
    else {
1403
0
  FcChar8 *s;
1404
0
  int      i;
1405
1406
0
  for (i = 0; i < e->num; i++) {
1407
0
      s = FcStrBuildFilename (e->strs[i], path, NULL);
1408
0
      FcStrFree (e->strs[i]);
1409
0
      e->strs[i] = s;
1410
0
  }
1411
0
    }
1412
104
    if (!FcStrSetInsert (e, retval, 0)) {
1413
0
  FcStrSetDestroy (e);
1414
0
  e = NULL;
1415
0
    }
1416
104
    FcStrFree (retval);
1417
1418
104
    return e;
1419
104
}
1420
1421
static void
1422
FcStartElement (void *userData, const XML_Char *name, const XML_Char **attr)
1423
312
{
1424
312
    FcConfigParse *parse = userData;
1425
312
    FcElement      element;
1426
1427
312
    element = FcElementMap (name);
1428
312
    if (element == FcElementUnknown)
1429
0
  FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1430
1431
312
    if (!FcPStackPush (parse, element, attr)) {
1432
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1433
0
  return;
1434
0
    }
1435
312
    return;
1436
312
}
1437
1438
static void
1439
FcParseRescan (FcConfigParse *parse)
1440
0
{
1441
0
    int n = FcVStackElements (parse);
1442
0
    while (n-- > 0) {
1443
0
  FcVStack *v = FcVStackFetch (parse, n);
1444
0
  if (v->tag != FcVStackInteger)
1445
0
      FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1446
0
  else
1447
0
      parse->config->rescanInterval = v->u.integer;
1448
0
    }
1449
0
}
1450
1451
static FcBool
1452
FcParseNil (FcConfigParse *parse)
1453
0
{
1454
0
    const FcChar8 *nil;
1455
1456
0
    if (!parse->pstack)
1457
0
  return FcFalse;
1458
0
    nil = FcConfigGetAttribute (parse, "xsi:nil");
1459
0
    if (!nil)
1460
0
  return FcFalse;
1461
0
    if (!FcConfigLexBool (parse, nil))
1462
0
  return FcFalse;
1463
0
    FcVStackPushNil (parse);
1464
1465
0
    return FcTrue;
1466
0
}
1467
1468
static void
1469
FcParseInt (FcConfigParse *parse)
1470
0
{
1471
0
    FcChar8 *s, *end;
1472
0
    int      l;
1473
1474
0
    if (!parse->pstack)
1475
0
  return;
1476
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1477
0
    if (!s) {
1478
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1479
0
  return;
1480
0
    }
1481
0
    if (FcParseNil (parse))
1482
0
  goto bail;
1483
0
    end = 0;
1484
0
    l = (int)strtol ((char *)s, (char **)&end, 0);
1485
0
    if (end != s + strlen ((char *)s))
1486
0
  FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1487
0
    else
1488
0
  FcVStackPushInteger (parse, l);
1489
0
bail:
1490
0
    FcStrBufDestroy (&parse->pstack->str);
1491
0
}
1492
1493
static void
1494
FcParseDouble (FcConfigParse *parse)
1495
0
{
1496
0
    FcChar8 *s, *end;
1497
0
    double   d;
1498
1499
0
    if (!parse->pstack)
1500
0
  return;
1501
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1502
0
    if (!s) {
1503
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1504
0
  return;
1505
0
    }
1506
0
    if (FcParseNil (parse))
1507
0
  goto bail;
1508
0
    end = 0;
1509
0
    d = FcStrtod ((char *)s, (char **)&end);
1510
0
    if (end != s + strlen ((char *)s))
1511
0
  FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1512
0
    else
1513
0
  FcVStackPushDouble (parse, d);
1514
0
bail:
1515
0
    FcStrBufDestroy (&parse->pstack->str);
1516
0
}
1517
1518
static void
1519
FcParseString (FcConfigParse *parse, FcVStackTag tag)
1520
0
{
1521
0
    FcChar8 *s;
1522
1523
0
    if (!parse->pstack)
1524
0
  return;
1525
0
    s = FcStrBufDone (&parse->pstack->str);
1526
0
    if (!s) {
1527
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1528
0
  return;
1529
0
    }
1530
0
    if (FcParseNil (parse)) {
1531
0
  FcStrFree (s);
1532
0
  return;
1533
0
    }
1534
0
    if (!FcVStackPushString (parse, tag, s))
1535
0
  FcStrFree (s);
1536
0
}
1537
1538
static void
1539
FcParseName (FcConfigParse *parse)
1540
0
{
1541
0
    const FcChar8 *kind_string;
1542
0
    FcMatchKind    kind;
1543
0
    FcChar8       *s;
1544
0
    FcObject       object;
1545
1546
0
    kind_string = FcConfigGetAttribute (parse, "target");
1547
0
    if (!kind_string)
1548
0
  kind = FcMatchDefault;
1549
0
    else {
1550
0
  if (!strcmp ((char *)kind_string, "pattern"))
1551
0
      kind = FcMatchPattern;
1552
0
  else if (!strcmp ((char *)kind_string, "font"))
1553
0
      kind = FcMatchFont;
1554
0
  else if (!strcmp ((char *)kind_string, "default"))
1555
0
      kind = FcMatchDefault;
1556
0
  else {
1557
0
      FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1558
0
      return;
1559
0
  }
1560
0
    }
1561
1562
0
    if (!parse->pstack)
1563
0
  return;
1564
0
    s = FcStrBufDone (&parse->pstack->str);
1565
0
    if (!s) {
1566
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1567
0
  return;
1568
0
    }
1569
0
    object = FcObjectFromName ((const char *)s);
1570
1571
0
    FcVStackPushName (parse, kind, object);
1572
1573
0
    FcStrFree (s);
1574
0
}
1575
1576
static void
1577
FcParseMatrix (FcConfigParse *parse)
1578
0
{
1579
0
    FcExprMatrix m;
1580
1581
0
    m.yy = FcPopExpr (parse);
1582
0
    m.yx = FcPopExpr (parse);
1583
0
    m.xy = FcPopExpr (parse);
1584
0
    m.xx = FcPopExpr (parse);
1585
1586
0
    if (!m.yy || !m.yx || !m.xy || !m.xx) {
1587
0
  FcConfigMessage (parse, FcSevereWarning, "Missing values in matrix element");
1588
0
  return;
1589
0
    }
1590
0
    if (FcPopExpr (parse))
1591
0
  FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1592
0
    else
1593
0
  FcVStackPushMatrix (parse, &m);
1594
0
}
1595
1596
static void
1597
FcParseRange (FcConfigParse *parse)
1598
0
{
1599
0
    FcVStack *vstack;
1600
0
    FcRange  *r;
1601
0
    FcChar32  n[2] = { 0, 0 };
1602
0
    int       count = 1;
1603
0
    double    d[2] = { 0.0L, 0.0L };
1604
0
    FcBool    dflag = FcFalse;
1605
1606
0
    while ((vstack = FcVStackPeek (parse))) {
1607
0
  if (count < 0) {
1608
0
      FcConfigMessage (parse, FcSevereError, "too many elements in range");
1609
0
      return;
1610
0
  }
1611
0
  switch ((int)vstack->tag) {
1612
0
  case FcVStackInteger:
1613
0
      if (dflag)
1614
0
    d[count] = (double)vstack->u.integer;
1615
0
      else
1616
0
    n[count] = vstack->u.integer;
1617
0
      break;
1618
0
  case FcVStackDouble:
1619
0
      if (count == 0 && !dflag)
1620
0
    d[1] = (double)n[1];
1621
0
      d[count] = vstack->u._double;
1622
0
      dflag = FcTrue;
1623
0
      break;
1624
0
  default:
1625
0
      FcConfigMessage (parse, FcSevereError, "invalid element in range");
1626
0
      if (dflag)
1627
0
    d[count] = 0.0L;
1628
0
      else
1629
0
    n[count] = 0;
1630
0
      break;
1631
0
  }
1632
0
  count--;
1633
0
  FcVStackPopAndDestroy (parse);
1634
0
    }
1635
0
    if (count >= 0) {
1636
0
  FcConfigMessage (parse, FcSevereError, "invalid range");
1637
0
  return;
1638
0
    }
1639
0
    if (dflag) {
1640
0
  if (d[0] > d[1]) {
1641
0
      FcConfigMessage (parse, FcSevereError, "invalid range");
1642
0
      return;
1643
0
  }
1644
0
  r = FcRangeCreateDouble (d[0], d[1]);
1645
0
    } else {
1646
0
  if (n[0] > n[1]) {
1647
0
      FcConfigMessage (parse, FcSevereError, "invalid range");
1648
0
      return;
1649
0
  }
1650
0
  r = FcRangeCreateInteger (n[0], n[1]);
1651
0
    }
1652
0
    FcVStackPushRange (parse, r);
1653
0
}
1654
1655
static FcBool
1656
FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1657
0
{
1658
0
    FcBool result = FcFalse;
1659
1660
0
    if (!FcNameBool (bool_, &result))
1661
0
  FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1662
0
                   bool_);
1663
0
    return result;
1664
0
}
1665
1666
static void
1667
FcParseBool (FcConfigParse *parse)
1668
0
{
1669
0
    FcChar8 *s;
1670
1671
0
    if (!parse->pstack)
1672
0
  return;
1673
0
    if (FcParseNil (parse))
1674
0
  goto bail;
1675
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1676
0
    if (!s) {
1677
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1678
0
  return;
1679
0
    }
1680
0
    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1681
0
bail:
1682
0
    FcStrBufDestroy (&parse->pstack->str);
1683
0
}
1684
1685
static void
1686
FcParseCharSet (FcConfigParse *parse)
1687
0
{
1688
0
    FcVStack  *vstack;
1689
0
    FcCharSet *charset = FcCharSetCreate();
1690
0
    FcChar32   i, begin, end;
1691
0
    int        n = 0;
1692
1693
0
    if (FcParseNil (parse))
1694
0
  goto bail;
1695
0
    while ((vstack = FcVStackPeek (parse))) {
1696
0
  switch ((int)vstack->tag) {
1697
0
  case FcVStackInteger:
1698
0
      if (!FcCharSetAddChar (charset, vstack->u.integer)) {
1699
0
    FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1700
0
      } else
1701
0
    n++;
1702
0
      break;
1703
0
  case FcVStackRange:
1704
0
      begin = (FcChar32)vstack->u.range->begin;
1705
0
      end = (FcChar32)vstack->u.range->end;
1706
1707
0
      if (begin <= end) {
1708
0
    for (i = begin; i <= end; i++) {
1709
0
        if (!FcCharSetAddChar (charset, i)) {
1710
0
      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1711
0
        } else
1712
0
      n++;
1713
0
    }
1714
0
      }
1715
0
      break;
1716
0
  default:
1717
0
      FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1718
0
      break;
1719
0
  }
1720
0
  FcVStackPopAndDestroy (parse);
1721
0
    }
1722
0
bail:
1723
0
    if (n > 0)
1724
0
  FcVStackPushCharSet (parse, charset);
1725
0
    else
1726
0
  FcCharSetDestroy (charset);
1727
0
}
1728
1729
static void
1730
FcParseLangSet (FcConfigParse *parse)
1731
0
{
1732
0
    FcVStack  *vstack;
1733
0
    FcLangSet *langset = FcLangSetCreate();
1734
0
    int        n = 0;
1735
1736
0
    if (FcParseNil (parse))
1737
0
  goto bail;
1738
0
    while ((vstack = FcVStackPeek (parse))) {
1739
0
  switch ((int)vstack->tag) {
1740
0
  case FcVStackString:
1741
0
      if (!FcLangSetAdd (langset, vstack->u.string)) {
1742
0
    FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1743
0
      } else
1744
0
    n++;
1745
0
      break;
1746
0
  default:
1747
0
      FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1748
0
      break;
1749
0
  }
1750
0
  FcVStackPopAndDestroy (parse);
1751
0
    }
1752
0
bail:
1753
0
    if (n > 0)
1754
0
  FcVStackPushLangSet (parse, langset);
1755
0
    else
1756
0
  FcLangSetDestroy (langset);
1757
0
}
1758
1759
static FcBool
1760
FcConfigLexBinding (FcConfigParse  *parse,
1761
                    const FcChar8  *binding_string,
1762
                    FcValueBinding *binding_ret)
1763
0
{
1764
0
    FcValueBinding binding;
1765
1766
0
    if (!binding_string)
1767
0
  binding = FcValueBindingWeak;
1768
0
    else {
1769
0
  if (!strcmp ((char *)binding_string, "weak"))
1770
0
      binding = FcValueBindingWeak;
1771
0
  else if (!strcmp ((char *)binding_string, "strong"))
1772
0
      binding = FcValueBindingStrong;
1773
0
  else if (!strcmp ((char *)binding_string, "same"))
1774
0
      binding = FcValueBindingSame;
1775
0
  else {
1776
0
      FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1777
0
      return FcFalse;
1778
0
  }
1779
0
    }
1780
0
    *binding_ret = binding;
1781
0
    return FcTrue;
1782
0
}
1783
1784
static void
1785
FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1786
0
{
1787
0
    FcVStack *vstack;
1788
0
    FcExpr   *left, *expr = 0, *newp;
1789
1790
0
    while ((vstack = FcVStackPeek (parse))) {
1791
0
  if (vstack->tag != FcVStackFamily) {
1792
0
      FcConfigMessage (parse, FcSevereWarning, "non-family");
1793
0
      FcVStackPopAndDestroy (parse);
1794
0
      continue;
1795
0
  }
1796
0
  left = vstack->u.expr;
1797
0
  vstack->tag = FcVStackNone;
1798
0
  FcVStackPopAndDestroy (parse);
1799
0
  if (expr) {
1800
0
      newp = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1801
0
      if (!newp) {
1802
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
1803
0
    FcExprDestroy (left);
1804
0
    FcExprDestroy (expr);
1805
0
    break;
1806
0
      }
1807
0
      expr = newp;
1808
0
  } else
1809
0
      expr = left;
1810
0
    }
1811
0
    if (expr) {
1812
0
  if (!FcVStackPushExpr (parse, tag, expr)) {
1813
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
1814
0
      FcExprDestroy (expr);
1815
0
  }
1816
0
    }
1817
0
}
1818
1819
static void
1820
FcParseFamily (FcConfigParse *parse)
1821
0
{
1822
0
    FcChar8 *s;
1823
0
    FcExpr  *expr;
1824
1825
0
    if (!parse->pstack)
1826
0
  return;
1827
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1828
0
    if (!s) {
1829
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1830
0
  return;
1831
0
    }
1832
0
    expr = FcExprCreateString (parse->config, s);
1833
0
    FcStrBufDestroy (&parse->pstack->str);
1834
0
    if (expr)
1835
0
  FcVStackPushExpr (parse, FcVStackFamily, expr);
1836
0
}
1837
1838
static void
1839
FcParseAlias (FcConfigParse *parse)
1840
0
{
1841
0
    FcExpr        *family = 0, *accept = 0, *prefer = 0, *def = 0, *newp = 0;
1842
0
    FcEdit        *edit = 0;
1843
0
    FcVStack      *vstack;
1844
0
    FcRule        *rule = NULL, *r;
1845
0
    FcValueBinding binding;
1846
0
    int            n;
1847
1848
0
    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1849
0
  return;
1850
0
    while ((vstack = FcVStackPeek (parse))) {
1851
0
  switch ((int)vstack->tag) {
1852
0
  case FcVStackFamily:
1853
0
      if (family) {
1854
0
    FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1855
0
    newp = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1856
0
    if (!newp)
1857
0
        FcConfigMessage (parse, FcSevereError, "out of memory");
1858
0
    else
1859
0
        family = newp;
1860
0
      } else
1861
0
    newp = vstack->u.expr;
1862
0
      if (newp) {
1863
0
    family = newp;
1864
0
    vstack->tag = FcVStackNone;
1865
0
      }
1866
0
      break;
1867
0
  case FcVStackPrefer:
1868
0
      if (prefer)
1869
0
    FcExprDestroy (prefer);
1870
0
      prefer = vstack->u.expr;
1871
0
      vstack->tag = FcVStackNone;
1872
0
      break;
1873
0
  case FcVStackAccept:
1874
0
      if (accept)
1875
0
    FcExprDestroy (accept);
1876
0
      accept = vstack->u.expr;
1877
0
      vstack->tag = FcVStackNone;
1878
0
      break;
1879
0
  case FcVStackDefault:
1880
0
      if (def)
1881
0
    FcExprDestroy (def);
1882
0
      def = vstack->u.expr;
1883
0
      vstack->tag = FcVStackNone;
1884
0
      break;
1885
0
  case FcVStackTest:
1886
0
      if (rule) {
1887
0
    r = FcRuleCreate (FcRuleTest, vstack->u.test);
1888
0
    r->next = rule;
1889
0
    rule = r;
1890
0
      } else
1891
0
    rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1892
0
      vstack->tag = FcVStackNone;
1893
0
      break;
1894
0
  default:
1895
0
      FcConfigMessage (parse, FcSevereWarning, "bad alias");
1896
0
      break;
1897
0
  }
1898
0
  FcVStackPopAndDestroy (parse);
1899
0
    }
1900
0
    if (!family) {
1901
0
  FcConfigMessage (parse, FcSevereError, "missing family in alias");
1902
0
  if (prefer)
1903
0
      FcExprDestroy (prefer);
1904
0
  if (accept)
1905
0
      FcExprDestroy (accept);
1906
0
  if (def)
1907
0
      FcExprDestroy (def);
1908
0
  if (rule)
1909
0
      FcRuleDestroy (rule);
1910
0
  return;
1911
0
    }
1912
0
    if (!prefer &&
1913
0
        !accept &&
1914
0
        !def) {
1915
0
  FcExprDestroy (family);
1916
0
  if (rule)
1917
0
      FcRuleDestroy (rule);
1918
0
  return;
1919
0
    } else {
1920
0
  FcTest *t = FcTestCreate (parse, FcMatchPattern,
1921
0
                            FcQualAny,
1922
0
                            (FcChar8 *)FC_FAMILY,
1923
0
                            FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1924
0
                            family);
1925
0
  if (rule) {
1926
0
      for (r = rule; r->next; r = r->next)
1927
0
    ;
1928
0
      r->next = FcRuleCreate (FcRuleTest, t);
1929
0
      r = r->next;
1930
0
  } else {
1931
0
      r = rule = FcRuleCreate (FcRuleTest, t);
1932
0
  }
1933
0
    }
1934
0
    if (prefer) {
1935
0
  edit = FcEditCreate (parse,
1936
0
                       FC_FAMILY_OBJECT,
1937
0
                       FcOpPrepend,
1938
0
                       prefer,
1939
0
                       binding);
1940
0
  if (!edit)
1941
0
      FcExprDestroy (prefer);
1942
0
  else {
1943
0
      r->next = FcRuleCreate (FcRuleEdit, edit);
1944
0
      r = r->next;
1945
0
  }
1946
0
    }
1947
0
    if (accept) {
1948
0
  edit = FcEditCreate (parse,
1949
0
                       FC_FAMILY_OBJECT,
1950
0
                       FcOpAppend,
1951
0
                       accept,
1952
0
                       binding);
1953
0
  if (!edit)
1954
0
      FcExprDestroy (accept);
1955
0
  else {
1956
0
      r->next = FcRuleCreate (FcRuleEdit, edit);
1957
0
      r = r->next;
1958
0
  }
1959
0
    }
1960
0
    if (def) {
1961
0
  edit = FcEditCreate (parse,
1962
0
                       FC_FAMILY_OBJECT,
1963
0
                       FcOpAppendLast,
1964
0
                       def,
1965
0
                       binding);
1966
0
  if (!edit)
1967
0
      FcExprDestroy (def);
1968
0
  else {
1969
0
      r->next = FcRuleCreate (FcRuleEdit, edit);
1970
0
      r = r->next;
1971
0
  }
1972
0
    }
1973
0
    if ((n = FcRuleSetAdd (parse->ruleset, rule, FcMatchPattern)) == -1)
1974
0
  FcRuleDestroy (rule);
1975
0
    else if (parse->config->maxObjects < n)
1976
0
  parse->config->maxObjects = n;
1977
0
}
1978
1979
static void
1980
FcParseDescription (FcConfigParse *parse)
1981
0
{
1982
0
    const FcChar8 *domain;
1983
0
    FcChar8       *desc;
1984
1985
0
    domain = FcConfigGetAttribute (parse, "domain");
1986
0
    desc = FcStrBufDone (&parse->pstack->str);
1987
0
    if (!desc) {
1988
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1989
0
  return;
1990
0
    }
1991
0
    FcRuleSetAddDescription (parse->ruleset, domain, desc);
1992
1993
0
    FcStrFree (desc);
1994
0
}
1995
1996
static void
1997
FcParseRemapDir (FcConfigParse *parse)
1998
0
{
1999
0
    const FcChar8 *path, *attr, *data, *salt;
2000
0
    FcStrSet      *prefix_dirs = NULL;
2001
2002
0
    data = FcStrBufDoneStatic (&parse->pstack->str);
2003
0
    if (!data) {
2004
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2005
0
  return;
2006
0
    }
2007
0
    if (data[0] == 0) {
2008
0
  FcConfigMessage (parse, FcSevereWarning, "empty font directory name for remap ignored");
2009
0
  return;
2010
0
    }
2011
0
    path = FcConfigGetAttribute (parse, "as-path");
2012
0
    if (!path) {
2013
0
  FcConfigMessage (parse, FcSevereWarning, "Missing as-path in remap-dir");
2014
0
  return;
2015
0
    }
2016
0
    attr = FcConfigGetAttribute (parse, "prefix");
2017
0
    salt = FcConfigGetAttribute (parse, "salt");
2018
0
    prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2019
0
    if (prefix_dirs) {
2020
0
  FcStrList *l = FcStrListCreate (prefix_dirs);
2021
0
  FcChar8   *prefix;
2022
2023
0
  FcStrSetDestroy (prefix_dirs);
2024
0
  while ((prefix = FcStrListNext (l))) {
2025
0
      if (!prefix || prefix[0] == 0) {
2026
    /* nop */
2027
0
      } else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome())) {
2028
0
    if (!FcConfigAddFontDir (parse->config, prefix, path, salt))
2029
0
        FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path);
2030
0
      }
2031
0
      FcStrBufDestroy (&parse->pstack->str);
2032
0
  }
2033
0
  FcStrListDone (l);
2034
0
    }
2035
0
}
2036
2037
static void
2038
FcParseResetDirs (FcConfigParse *parse)
2039
0
{
2040
0
    if (!parse->scanOnly) {
2041
0
  if (!FcConfigResetFontDirs (parse->config))
2042
0
      FcConfigMessage (parse, FcSevereError, "Unable to reset fonts dirs");
2043
0
    }
2044
0
}
2045
2046
static FcExpr *
2047
FcPopExpr (FcConfigParse *parse)
2048
0
{
2049
0
    FcVStack *vstack = FcVStackPeek (parse);
2050
0
    FcExpr   *expr = 0;
2051
0
    if (!vstack)
2052
0
  return 0;
2053
0
    switch ((int)vstack->tag) {
2054
0
    case FcVStackNone:
2055
0
  break;
2056
0
    case FcVStackString:
2057
0
    case FcVStackFamily:
2058
0
  expr = FcExprCreateString (parse->config, vstack->u.string);
2059
0
  break;
2060
0
    case FcVStackName:
2061
0
  expr = FcExprCreateName (parse->config, vstack->u.name);
2062
0
  break;
2063
0
    case FcVStackConstant:
2064
0
  expr = FcExprCreateConst (parse->config, vstack->u.string);
2065
0
  break;
2066
0
    case FcVStackGlob:
2067
  /* XXX: What's the correct action here? (CDW) */
2068
0
  break;
2069
0
    case FcVStackPrefer:
2070
0
    case FcVStackAccept:
2071
0
    case FcVStackDefault:
2072
0
  expr = vstack->u.expr;
2073
0
  vstack->tag = FcVStackNone;
2074
0
  break;
2075
0
    case FcVStackInteger:
2076
0
  expr = FcExprCreateInteger (parse->config, vstack->u.integer);
2077
0
  break;
2078
0
    case FcVStackDouble:
2079
0
  expr = FcExprCreateDouble (parse->config, vstack->u._double);
2080
0
  break;
2081
0
    case FcVStackMatrix:
2082
0
  expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
2083
0
  break;
2084
0
    case FcVStackRange:
2085
0
  expr = FcExprCreateRange (parse->config, vstack->u.range);
2086
0
  break;
2087
0
    case FcVStackBool:
2088
0
  expr = FcExprCreateBool (parse->config, vstack->u.bool_);
2089
0
  break;
2090
0
    case FcVStackCharSet:
2091
0
  expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
2092
0
  break;
2093
0
    case FcVStackLangSet:
2094
0
  expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
2095
0
  break;
2096
0
    case FcVStackTest:
2097
0
  break;
2098
0
    case FcVStackExpr:
2099
0
  expr = vstack->u.expr;
2100
0
  vstack->tag = FcVStackNone;
2101
0
  break;
2102
0
    case FcVStackEdit:
2103
0
  break;
2104
0
    case FcVStackNil:
2105
0
  expr = FcExprCreateNil (parse->config);
2106
0
  break;
2107
0
    default:
2108
0
  break;
2109
0
    }
2110
0
    FcVStackPopAndDestroy (parse);
2111
0
    return expr;
2112
0
}
2113
2114
/*
2115
 * This builds a tree of binary operations.  Note
2116
 * that every operator is defined so that if only
2117
 * a single operand is contained, the value of the
2118
 * whole expression is the value of the operand.
2119
 *
2120
 * This code reduces in that case to returning that
2121
 * operand.
2122
 */
2123
static FcExpr *
2124
FcPopBinary (FcConfigParse *parse, FcOp op)
2125
0
{
2126
0
    FcExpr *left, *expr = 0, *newp;
2127
2128
0
    while ((left = FcPopExpr (parse))) {
2129
0
  if (expr) {
2130
0
      newp = FcExprCreateOp (parse->config, left, op, expr);
2131
0
      if (!newp) {
2132
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
2133
0
    FcExprDestroy (left);
2134
0
    FcExprDestroy (expr);
2135
0
    return 0;
2136
0
      }
2137
0
      expr = newp;
2138
0
  } else
2139
0
      expr = left;
2140
0
    }
2141
0
    return expr;
2142
0
}
2143
2144
static void
2145
FcParseBinary (FcConfigParse *parse, FcOp op)
2146
0
{
2147
0
    FcExpr *expr = FcPopBinary (parse, op);
2148
0
    if (expr)
2149
0
  FcVStackPushExpr (parse, FcVStackExpr, expr);
2150
0
}
2151
2152
/*
2153
 * This builds a a unary operator, it consumes only
2154
 * a single operand
2155
 */
2156
2157
static FcExpr *
2158
FcPopUnary (FcConfigParse *parse, FcOp op)
2159
0
{
2160
0
    FcExpr *operand, *newp = 0;
2161
2162
0
    if ((operand = FcPopExpr (parse))) {
2163
0
  newp = FcExprCreateOp (parse->config, operand, op, 0);
2164
0
  if (!newp) {
2165
0
      FcExprDestroy (operand);
2166
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2167
0
  }
2168
0
    }
2169
0
    return newp;
2170
0
}
2171
2172
static void
2173
FcParseUnary (FcConfigParse *parse, FcOp op)
2174
0
{
2175
0
    FcExpr *expr = FcPopUnary (parse, op);
2176
0
    if (expr)
2177
0
  FcVStackPushExpr (parse, FcVStackExpr, expr);
2178
0
}
2179
2180
static void
2181
FcParseDir (FcConfigParse *parse)
2182
104
{
2183
104
    const FcChar8 *attr, *data, *salt;
2184
104
    FcStrSet      *prefix_dirs = NULL;
2185
2186
104
    data = FcStrBufDoneStatic (&parse->pstack->str);
2187
104
    if (!data) {
2188
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2189
0
  return;
2190
0
    }
2191
104
    if (data[0] == 0) {
2192
0
  FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2193
0
  return;
2194
0
    }
2195
104
    attr = FcConfigGetAttribute (parse, "prefix");
2196
104
    salt = FcConfigGetAttribute (parse, "salt");
2197
104
    prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2198
104
    if (prefix_dirs) {
2199
104
  FcStrList *l = FcStrListCreate (prefix_dirs);
2200
104
  FcChar8   *prefix;
2201
2202
104
  FcStrSetDestroy (prefix_dirs);
2203
208
  while ((prefix = FcStrListNext (l))) {
2204
104
      if (!prefix || prefix[0] == 0) {
2205
    /* nop */
2206
104
      } else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome())) {
2207
104
    if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt))
2208
0
        FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix);
2209
104
      }
2210
104
      FcStrBufDestroy (&parse->pstack->str);
2211
104
  }
2212
104
  FcStrListDone (l);
2213
104
    }
2214
104
}
2215
2216
static void
2217
FcParseCacheDir (FcConfigParse *parse)
2218
104
{
2219
104
    const FcChar8 *attr;
2220
104
    FcChar8       *prefix = NULL, *p, *data = NULL;
2221
2222
104
    attr = FcConfigGetAttribute (parse, "prefix");
2223
104
    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) {
2224
0
  prefix = FcConfigXdgCacheHome();
2225
  /* home directory might be disabled.
2226
   * simply ignore this element.
2227
   */
2228
0
  if (!prefix)
2229
0
      goto bail;
2230
0
    }
2231
104
    data = FcStrBufDone (&parse->pstack->str);
2232
104
    if (!data) {
2233
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2234
0
  data = prefix;
2235
0
  goto bail;
2236
0
    }
2237
104
    if (data[0] == 0) {
2238
0
  FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2239
0
  FcStrFree (data);
2240
0
  data = prefix;
2241
0
  goto bail;
2242
0
    }
2243
104
    if (prefix) {
2244
0
  size_t plen = strlen ((const char *)prefix);
2245
0
  size_t dlen = strlen ((const char *)data);
2246
2247
0
  p = realloc (prefix, plen + 1 + dlen + 1);
2248
0
  if (!p) {
2249
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2250
0
      FcStrFree (prefix);
2251
0
      goto bail;
2252
0
  }
2253
0
  prefix = p;
2254
0
  prefix[plen] = FC_DIR_SEPARATOR;
2255
0
  memcpy (&prefix[plen + 1], data, dlen);
2256
0
  prefix[plen + 1 + dlen] = 0;
2257
0
  FcStrFree (data);
2258
0
  data = prefix;
2259
0
    }
2260
#ifdef _WIN32
2261
    else if (data[0] == '/' && fontconfig_instprefix[0] != '\0') {
2262
  size_t plen = strlen ((const char *)fontconfig_instprefix);
2263
  size_t dlen = strlen ((const char *)data);
2264
2265
  prefix = malloc (plen + 1 + dlen + 1);
2266
  if (!prefix) {
2267
      FcConfigMessage (parse, FcSevereError, "out of memory");
2268
      goto bail;
2269
  }
2270
  strcpy ((char *)prefix, (char *)fontconfig_instprefix);
2271
  prefix[plen] = FC_DIR_SEPARATOR;
2272
  memcpy (&prefix[plen + 1], data, dlen);
2273
  prefix[plen + 1 + dlen] = 0;
2274
  FcStrFree (data);
2275
  data = prefix;
2276
    } else if (strcmp ((const char *)data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) {
2277
  int rc;
2278
2279
  FcStrFree (data);
2280
  data = malloc (1000);
2281
  if (!data) {
2282
      FcConfigMessage (parse, FcSevereError, "out of memory");
2283
      goto bail;
2284
  }
2285
  rc = GetTempPath (800, (LPSTR)data);
2286
  if (rc == 0 || rc > 800) {
2287
      FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2288
      goto bail;
2289
  }
2290
  if (data[strlen ((const char *)data) - 1] != '\\')
2291
      strcat ((char *)data, "\\");
2292
  strcat ((char *)data, "fontconfig\\cache");
2293
    } else if (strcmp ((const char *)data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0) {
2294
  char   szFPath[MAX_PATH + 1];
2295
  size_t len;
2296
2297
  if (!(pSHGetFolderPathA && SUCCEEDED (pSHGetFolderPathA (NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath)))) {
2298
      FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2299
      goto bail;
2300
  }
2301
  strncat (szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen (szFPath));
2302
  len = strlen (szFPath) + 1;
2303
  FcStrFree (data);
2304
  data = malloc (len);
2305
  if (!data) {
2306
      FcConfigMessage (parse, FcSevereError, "out of memory");
2307
      goto bail;
2308
  }
2309
  strncpy ((char *)data, szFPath, len);
2310
    }
2311
#endif
2312
104
    if (strlen ((char *)data) == 0)
2313
0
  FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2314
104
    else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome())) {
2315
104
  if (!FcConfigAddCacheDir (parse->config, data))
2316
0
      FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2317
104
    }
2318
104
    FcStrBufDestroy (&parse->pstack->str);
2319
2320
104
bail:
2321
104
    if (data)
2322
104
  FcStrFree (data);
2323
104
}
2324
2325
static void
2326
FcParseInclude (FcConfigParse *parse)
2327
0
{
2328
0
    FcChar8       *s;
2329
0
    const FcChar8 *attr;
2330
0
    FcBool         ignore_missing = FcFalse;
2331
0
    FcChar8       *prefix = NULL, *p;
2332
0
    FcRuleSet     *ruleset;
2333
0
    FcMatchKind    k;
2334
2335
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
2336
0
    if (!s) {
2337
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2338
0
  goto bail;
2339
0
    }
2340
0
    attr = FcConfigGetAttribute (parse, "ignore_missing");
2341
0
    ignore_missing = attr ? FcConfigLexBool (parse, (FcChar8 *)attr) : FcFalse;
2342
    /* deprecated attribute has ever been used to mark
2343
     * old configuration path as deprecated.
2344
     * We don't have any code for it but just keep it for
2345
     * backward compatibility.
2346
     */
2347
0
    attr = FcConfigGetAttribute (parse, "deprecated");
2348
0
    attr = FcConfigGetAttribute (parse, "prefix");
2349
0
    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) {
2350
0
  prefix = FcConfigXdgConfigHome();
2351
  /* home directory might be disabled.
2352
   * simply ignore this element.
2353
   */
2354
0
  if (!prefix)
2355
0
      goto bail;
2356
0
    }
2357
0
    if (prefix) {
2358
0
  size_t plen = strlen ((const char *)prefix);
2359
0
  size_t dlen = strlen ((const char *)s);
2360
2361
0
  p = realloc (prefix, plen + 1 + dlen + 1);
2362
0
  if (!p) {
2363
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2364
0
      goto bail;
2365
0
  }
2366
0
  prefix = p;
2367
0
  prefix[plen] = FC_DIR_SEPARATOR;
2368
0
  memcpy (&prefix[plen + 1], s, dlen);
2369
0
  prefix[plen + 1 + dlen] = 0;
2370
0
  s = prefix;
2371
0
    }
2372
    /* flush the ruleset into the queue */
2373
0
    ruleset = parse->ruleset;
2374
0
    parse->ruleset = FcRuleSetCreate (ruleset->name);
2375
0
    FcRuleSetEnable (parse->ruleset, ruleset->enabled);
2376
0
    FcRuleSetAddDescription (parse->ruleset, ruleset->domain, ruleset->description);
2377
0
    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) {
2378
0
  FcPtrListIter iter;
2379
2380
0
  FcPtrListIterInit (ruleset->subst[k], &iter);
2381
0
  if (FcPtrListIterIsValid (ruleset->subst[k], &iter)) {
2382
0
      FcPtrListIterInitAtLast (parse->config->subst[k], &iter);
2383
0
      FcRuleSetReference (ruleset);
2384
0
      FcPtrListIterAdd (parse->config->subst[k], &iter, ruleset);
2385
0
  }
2386
0
    }
2387
0
    FcRuleSetDestroy (ruleset);
2388
0
    if (!_FcConfigParse (parse->config, s, !ignore_missing, !parse->scanOnly))
2389
0
  parse->error = FcTrue;
2390
0
    FcStrBufDestroy (&parse->pstack->str);
2391
2392
0
bail:
2393
0
    if (prefix)
2394
0
  FcStrFree (prefix);
2395
0
}
2396
2397
typedef struct _FcOpMap {
2398
    char name[16];
2399
    FcOp op;
2400
} FcOpMap;
2401
2402
static FcOp
2403
FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2404
0
{
2405
0
    int i;
2406
2407
0
    for (i = 0; i < nmap; i++)
2408
0
  if (!strcmp ((char *)op, map[i].name))
2409
0
      return map[i].op;
2410
0
    return FcOpInvalid;
2411
0
}
2412
2413
static const FcOpMap fcCompareOps[] = {
2414
    { "eq",           FcOpEqual       },
2415
    { "not_eq",       FcOpNotEqual    },
2416
    { "less",         FcOpLess        },
2417
    { "less_eq",      FcOpLessEqual   },
2418
    { "more",         FcOpMore        },
2419
    { "more_eq",      FcOpMoreEqual   },
2420
    { "contains",     FcOpContains    },
2421
    { "not_contains", FcOpNotContains }
2422
};
2423
2424
0
#define NUM_COMPARE_OPS (int)(sizeof fcCompareOps / sizeof fcCompareOps[0])
2425
2426
static FcOp
2427
FcConfigLexCompare (const FcChar8 *compare)
2428
0
{
2429
0
    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2430
0
}
2431
2432
static void
2433
FcParseTest (FcConfigParse *parse)
2434
0
{
2435
0
    const FcChar8 *kind_string;
2436
0
    FcMatchKind    kind;
2437
0
    const FcChar8 *qual_string;
2438
0
    FcQual         qual;
2439
0
    const FcChar8 *name;
2440
0
    const FcChar8 *compare_string;
2441
0
    FcOp           compare;
2442
0
    FcExpr        *expr;
2443
0
    FcTest        *test;
2444
0
    const FcChar8 *iblanks_string;
2445
0
    int            flags = 0;
2446
2447
0
    kind_string = FcConfigGetAttribute (parse, "target");
2448
0
    if (!kind_string)
2449
0
  kind = FcMatchDefault;
2450
0
    else {
2451
0
  if (!strcmp ((char *)kind_string, "pattern"))
2452
0
      kind = FcMatchPattern;
2453
0
  else if (!strcmp ((char *)kind_string, "font"))
2454
0
      kind = FcMatchFont;
2455
0
  else if (!strcmp ((char *)kind_string, "scan"))
2456
0
      kind = FcMatchScan;
2457
0
  else if (!strcmp ((char *)kind_string, "default"))
2458
0
      kind = FcMatchDefault;
2459
0
  else {
2460
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2461
0
      return;
2462
0
  }
2463
0
    }
2464
0
    qual_string = FcConfigGetAttribute (parse, "qual");
2465
0
    if (!qual_string)
2466
0
  qual = FcQualAny;
2467
0
    else {
2468
0
  if (!strcmp ((char *)qual_string, "any"))
2469
0
      qual = FcQualAny;
2470
0
  else if (!strcmp ((char *)qual_string, "all"))
2471
0
      qual = FcQualAll;
2472
0
  else if (!strcmp ((char *)qual_string, "first"))
2473
0
      qual = FcQualFirst;
2474
0
  else if (!strcmp ((char *)qual_string, "not_first"))
2475
0
      qual = FcQualNotFirst;
2476
0
  else {
2477
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2478
0
      return;
2479
0
  }
2480
0
    }
2481
0
    name = FcConfigGetAttribute (parse, "name");
2482
0
    if (!name) {
2483
0
  FcConfigMessage (parse, FcSevereWarning, "missing test name");
2484
0
  return;
2485
0
    }
2486
0
    compare_string = FcConfigGetAttribute (parse, "compare");
2487
0
    if (!compare_string)
2488
0
  compare = FcOpEqual;
2489
0
    else {
2490
0
  compare = FcConfigLexCompare (compare_string);
2491
0
  if (compare == FcOpInvalid) {
2492
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2493
0
      return;
2494
0
  }
2495
0
    }
2496
0
    iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2497
0
    if (iblanks_string) {
2498
0
  if (FcConfigLexBool (parse, iblanks_string)) {
2499
0
      flags |= FcOpFlagIgnoreBlanks;
2500
0
  }
2501
0
    }
2502
0
    expr = FcPopBinary (parse, FcOpComma);
2503
0
    if (!expr) {
2504
0
  FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2505
0
  return;
2506
0
    }
2507
0
    if (expr->op == FcOpComma) {
2508
0
  FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2509
0
    }
2510
0
    test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2511
0
    if (!test) {
2512
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2513
0
  return;
2514
0
    }
2515
0
    FcVStackPushTest (parse, test);
2516
0
}
2517
2518
static const FcOpMap fcModeOps[] = {
2519
    { "assign",         FcOpAssign        },
2520
    { "assign_replace", FcOpAssignReplace },
2521
    { "prepend",        FcOpPrepend       },
2522
    { "prepend_first",  FcOpPrependFirst  },
2523
    { "append",         FcOpAppend        },
2524
    { "append_last",    FcOpAppendLast    },
2525
    { "delete",         FcOpDelete        },
2526
    { "delete_all",     FcOpDeleteAll     },
2527
};
2528
2529
0
#define NUM_MODE_OPS (int)(sizeof fcModeOps / sizeof fcModeOps[0])
2530
2531
static FcOp
2532
FcConfigLexMode (const FcChar8 *mode)
2533
0
{
2534
0
    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2535
0
}
2536
2537
static void
2538
FcParseEdit (FcConfigParse *parse)
2539
0
{
2540
0
    const FcChar8 *name;
2541
0
    const FcChar8 *mode_string;
2542
0
    FcOp           mode;
2543
0
    FcValueBinding binding;
2544
0
    FcExpr        *expr;
2545
0
    FcEdit        *edit;
2546
2547
0
    name = FcConfigGetAttribute (parse, "name");
2548
0
    if (!name) {
2549
0
  FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2550
0
  return;
2551
0
    }
2552
0
    mode_string = FcConfigGetAttribute (parse, "mode");
2553
0
    if (!mode_string)
2554
0
  mode = FcOpAssign;
2555
0
    else {
2556
0
  mode = FcConfigLexMode (mode_string);
2557
0
  if (mode == FcOpInvalid) {
2558
0
      FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2559
0
      return;
2560
0
  }
2561
0
    }
2562
0
    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2563
0
  return;
2564
2565
0
    expr = FcPopBinary (parse, FcOpComma);
2566
0
    if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2567
0
        expr != NULL) {
2568
0
  FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2569
0
  FcExprDestroy (expr);
2570
0
  expr = NULL;
2571
0
    }
2572
0
    edit = FcEditCreate (parse, FcObjectFromName ((char *)name),
2573
0
                         mode, expr, binding);
2574
0
    if (!edit) {
2575
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2576
0
  FcExprDestroy (expr);
2577
0
  return;
2578
0
    }
2579
0
    if (!FcVStackPushEdit (parse, edit))
2580
0
  FcEditDestroy (edit);
2581
0
}
2582
2583
static void
2584
FcParseMatch (FcConfigParse *parse)
2585
0
{
2586
0
    const FcChar8 *kind_name;
2587
0
    FcMatchKind    kind;
2588
0
    FcVStack      *vstack;
2589
0
    FcRule        *rule = NULL, *r;
2590
0
    int            n;
2591
2592
0
    kind_name = FcConfigGetAttribute (parse, "target");
2593
0
    if (!kind_name)
2594
0
  kind = FcMatchPattern;
2595
0
    else {
2596
0
  if (!strcmp ((char *)kind_name, "pattern"))
2597
0
      kind = FcMatchPattern;
2598
0
  else if (!strcmp ((char *)kind_name, "font"))
2599
0
      kind = FcMatchFont;
2600
0
  else if (!strcmp ((char *)kind_name, "scan"))
2601
0
      kind = FcMatchScan;
2602
0
  else {
2603
0
      FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2604
0
      return;
2605
0
  }
2606
0
    }
2607
0
    while ((vstack = FcVStackPeek (parse))) {
2608
0
  switch ((int)vstack->tag) {
2609
0
  case FcVStackTest:
2610
0
      r = FcRuleCreate (FcRuleTest, vstack->u.test);
2611
0
      if (rule)
2612
0
    r->next = rule;
2613
0
      rule = r;
2614
0
      vstack->tag = FcVStackNone;
2615
0
      break;
2616
0
  case FcVStackEdit:
2617
0
      if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT) {
2618
0
    FcConfigMessage (parse, FcSevereError,
2619
0
                     "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2620
0
                     FcObjectName (vstack->u.edit->object));
2621
0
    if (rule)
2622
0
        FcRuleDestroy (rule);
2623
0
    return;
2624
0
      }
2625
0
      r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2626
0
      if (rule)
2627
0
    r->next = rule;
2628
0
      rule = r;
2629
0
      vstack->tag = FcVStackNone;
2630
0
      break;
2631
0
  default:
2632
0
      FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2633
0
      break;
2634
0
  }
2635
0
  FcVStackPopAndDestroy (parse);
2636
0
    }
2637
0
    if (!rule) {
2638
0
  FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2639
0
  return;
2640
0
    }
2641
0
    if ((n = FcRuleSetAdd (parse->ruleset, rule, kind)) == -1) {
2642
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2643
0
  FcRuleDestroy (rule);
2644
0
    } else if (parse->config->maxObjects < n)
2645
0
  parse->config->maxObjects = n;
2646
0
}
2647
2648
static void
2649
FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2650
0
{
2651
0
    FcVStack *vstack;
2652
2653
0
    while ((vstack = FcVStackPeek (parse))) {
2654
0
  switch ((int)vstack->tag) {
2655
0
  case FcVStackGlob:
2656
0
      if (!parse->scanOnly && !FcConfigGlobAdd (parse->config,
2657
0
                                                vstack->u.string,
2658
0
                                                element == FcElementAcceptfont)) {
2659
0
    if (FcStrUsesHome (vstack->u.string) && FcConfigHome() == NULL)
2660
0
        FcConfigMessage (parse, FcSevereWarning, "Home is disabled");
2661
0
    else
2662
0
        FcConfigMessage (parse, FcSevereError, "out of memory");
2663
0
      } else {
2664
0
    if (parse->scanOnly && vstack->u.string) {
2665
0
        FcStrFree (vstack->u.string);
2666
0
        vstack->tag = FcVStackNone;
2667
0
    }
2668
0
      }
2669
0
      break;
2670
0
  case FcVStackPattern:
2671
0
      if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
2672
0
                                                    vstack->u.pattern,
2673
0
                                                    element == FcElementAcceptfont)) {
2674
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
2675
0
      } else {
2676
0
    if (parse->scanOnly && vstack->u.pattern)
2677
0
        FcPatternDestroy (vstack->u.pattern);
2678
0
    vstack->tag = FcVStackNone;
2679
0
      }
2680
0
      break;
2681
0
  default:
2682
0
      FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2683
0
      break;
2684
0
  }
2685
0
  FcVStackPopAndDestroy (parse);
2686
0
    }
2687
0
}
2688
2689
static FcValue
2690
FcPopValue (FcConfigParse *parse)
2691
0
{
2692
0
    FcVStack *vstack = FcVStackPeek (parse);
2693
0
    FcValue   value;
2694
2695
0
    value.type = FcTypeVoid;
2696
2697
0
    if (!vstack)
2698
0
  return value;
2699
2700
0
    switch ((int)vstack->tag) {
2701
0
    case FcVStackString:
2702
0
  value.u.s = FcStrCopy (vstack->u.string);
2703
0
  if (value.u.s)
2704
0
      value.type = FcTypeString;
2705
0
  break;
2706
0
    case FcVStackConstant:
2707
0
  if (FcNameConstant (vstack->u.string, &value.u.i))
2708
0
      value.type = FcTypeInteger;
2709
0
  break;
2710
0
    case FcVStackInteger:
2711
0
  value.u.i = vstack->u.integer;
2712
0
  value.type = FcTypeInteger;
2713
0
  break;
2714
0
    case FcVStackDouble:
2715
0
  value.u.d = vstack->u._double;
2716
0
  value.type = FcTypeDouble;
2717
0
  break;
2718
0
    case FcVStackBool:
2719
0
  value.u.b = vstack->u.bool_;
2720
0
  value.type = FcTypeBool;
2721
0
  break;
2722
0
    case FcVStackCharSet:
2723
0
  value.u.c = FcCharSetCopy (vstack->u.charset);
2724
0
  if (value.u.c)
2725
0
      value.type = FcTypeCharSet;
2726
0
  break;
2727
0
    case FcVStackLangSet:
2728
0
  value.u.l = FcLangSetCopy (vstack->u.langset);
2729
0
  if (value.u.l)
2730
0
      value.type = FcTypeLangSet;
2731
0
  break;
2732
0
    case FcVStackRange:
2733
0
  value.u.r = FcRangeCopy (vstack->u.range);
2734
0
  if (value.u.r)
2735
0
      value.type = FcTypeRange;
2736
0
  break;
2737
0
    default:
2738
0
  FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2739
0
                   vstack->tag);
2740
0
  break;
2741
0
    }
2742
0
    FcVStackPopAndDestroy (parse);
2743
2744
0
    return value;
2745
0
}
2746
2747
static void
2748
FcParsePatelt (FcConfigParse *parse)
2749
0
{
2750
0
    FcValue     value;
2751
0
    FcPattern  *pattern = FcPatternCreate();
2752
0
    const char *name;
2753
2754
0
    if (!pattern) {
2755
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2756
0
  return;
2757
0
    }
2758
2759
0
    name = (char *)FcConfigGetAttribute (parse, "name");
2760
0
    if (!name) {
2761
0
  FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2762
0
  FcPatternDestroy (pattern);
2763
0
  return;
2764
0
    }
2765
2766
0
    for (;;) {
2767
0
  value = FcPopValue (parse);
2768
0
  if (value.type == FcTypeVoid)
2769
0
      break;
2770
0
  if (!FcPatternAdd (pattern, name, value, FcTrue)) {
2771
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2772
0
      FcValueDestroy (value);
2773
0
      break;
2774
0
  }
2775
0
  FcValueDestroy (value);
2776
0
    }
2777
2778
0
    FcVStackPushPattern (parse, pattern);
2779
0
}
2780
2781
static void
2782
FcParsePattern (FcConfigParse *parse)
2783
0
{
2784
0
    FcVStack  *vstack;
2785
0
    FcPattern *pattern = FcPatternCreate();
2786
2787
0
    if (!pattern) {
2788
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2789
0
  return;
2790
0
    }
2791
2792
0
    while ((vstack = FcVStackPeek (parse))) {
2793
0
  switch ((int)vstack->tag) {
2794
0
  case FcVStackPattern:
2795
0
      if (!FcPatternAppend (pattern, vstack->u.pattern)) {
2796
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
2797
0
    FcPatternDestroy (pattern);
2798
0
    return;
2799
0
      }
2800
0
      break;
2801
0
  default:
2802
0
      FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2803
0
      break;
2804
0
  }
2805
0
  FcVStackPopAndDestroy (parse);
2806
0
    }
2807
2808
0
    FcVStackPushPattern (parse, pattern);
2809
0
}
2810
2811
static void
2812
FcEndElement (void *userData, const XML_Char *name FC_UNUSED)
2813
312
{
2814
312
    FcConfigParse *parse = userData;
2815
312
    FcChar8       *data;
2816
2817
312
    if (!parse->pstack)
2818
0
  return;
2819
312
    switch (parse->pstack->element) {
2820
0
    case FcElementNone:
2821
0
  break;
2822
104
    case FcElementFontconfig:
2823
104
  break;
2824
104
    case FcElementDir:
2825
104
  FcParseDir (parse);
2826
104
  break;
2827
104
    case FcElementCacheDir:
2828
104
  FcParseCacheDir (parse);
2829
104
  break;
2830
0
    case FcElementCache:
2831
0
  data = FcStrBufDoneStatic (&parse->pstack->str);
2832
0
  if (!data) {
2833
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2834
0
      break;
2835
0
  }
2836
  /* discard this data; no longer used */
2837
0
  FcStrBufDestroy (&parse->pstack->str);
2838
0
  break;
2839
0
    case FcElementInclude:
2840
0
  FcParseInclude (parse);
2841
0
  break;
2842
0
    case FcElementConfig:
2843
0
  break;
2844
0
    case FcElementMatch:
2845
0
  FcParseMatch (parse);
2846
0
  break;
2847
0
    case FcElementAlias:
2848
0
  FcParseAlias (parse);
2849
0
  break;
2850
0
    case FcElementDescription:
2851
0
  FcParseDescription (parse);
2852
0
  break;
2853
0
    case FcElementRemapDir:
2854
0
  FcParseRemapDir (parse);
2855
0
  break;
2856
0
    case FcElementResetDirs:
2857
0
  FcParseResetDirs (parse);
2858
0
  break;
2859
2860
0
    case FcElementRescan:
2861
0
  FcParseRescan (parse);
2862
0
  break;
2863
2864
0
    case FcElementPrefer:
2865
0
  FcParseFamilies (parse, FcVStackPrefer);
2866
0
  break;
2867
0
    case FcElementAccept:
2868
0
  FcParseFamilies (parse, FcVStackAccept);
2869
0
  break;
2870
0
    case FcElementDefault:
2871
0
  FcParseFamilies (parse, FcVStackDefault);
2872
0
  break;
2873
0
    case FcElementFamily:
2874
0
  FcParseFamily (parse);
2875
0
  break;
2876
2877
0
    case FcElementTest:
2878
0
  FcParseTest (parse);
2879
0
  break;
2880
0
    case FcElementEdit:
2881
0
  FcParseEdit (parse);
2882
0
  break;
2883
2884
0
    case FcElementInt:
2885
0
  FcParseInt (parse);
2886
0
  break;
2887
0
    case FcElementDouble:
2888
0
  FcParseDouble (parse);
2889
0
  break;
2890
0
    case FcElementString:
2891
0
  FcParseString (parse, FcVStackString);
2892
0
  break;
2893
0
    case FcElementMatrix:
2894
0
  FcParseMatrix (parse);
2895
0
  break;
2896
0
    case FcElementRange:
2897
0
  FcParseRange (parse);
2898
0
  break;
2899
0
    case FcElementBool:
2900
0
  FcParseBool (parse);
2901
0
  break;
2902
0
    case FcElementCharSet:
2903
0
  FcParseCharSet (parse);
2904
0
  break;
2905
0
    case FcElementLangSet:
2906
0
  FcParseLangSet (parse);
2907
0
  break;
2908
0
    case FcElementSelectfont:
2909
0
  break;
2910
0
    case FcElementAcceptfont:
2911
0
    case FcElementRejectfont:
2912
0
  FcParseAcceptRejectFont (parse, parse->pstack->element);
2913
0
  break;
2914
0
    case FcElementGlob:
2915
0
  FcParseString (parse, FcVStackGlob);
2916
0
  break;
2917
0
    case FcElementPattern:
2918
0
  FcParsePattern (parse);
2919
0
  break;
2920
0
    case FcElementPatelt:
2921
0
  FcParsePatelt (parse);
2922
0
  break;
2923
0
    case FcElementName:
2924
0
  FcParseName (parse);
2925
0
  break;
2926
0
    case FcElementConst:
2927
0
  FcParseString (parse, FcVStackConstant);
2928
0
  break;
2929
0
    case FcElementOr:
2930
0
  FcParseBinary (parse, FcOpOr);
2931
0
  break;
2932
0
    case FcElementAnd:
2933
0
  FcParseBinary (parse, FcOpAnd);
2934
0
  break;
2935
0
    case FcElementEq:
2936
0
  FcParseBinary (parse, FcOpEqual);
2937
0
  break;
2938
0
    case FcElementNotEq:
2939
0
  FcParseBinary (parse, FcOpNotEqual);
2940
0
  break;
2941
0
    case FcElementLess:
2942
0
  FcParseBinary (parse, FcOpLess);
2943
0
  break;
2944
0
    case FcElementLessEq:
2945
0
  FcParseBinary (parse, FcOpLessEqual);
2946
0
  break;
2947
0
    case FcElementMore:
2948
0
  FcParseBinary (parse, FcOpMore);
2949
0
  break;
2950
0
    case FcElementMoreEq:
2951
0
  FcParseBinary (parse, FcOpMoreEqual);
2952
0
  break;
2953
0
    case FcElementContains:
2954
0
  FcParseBinary (parse, FcOpContains);
2955
0
  break;
2956
0
    case FcElementNotContains:
2957
0
  FcParseBinary (parse, FcOpNotContains);
2958
0
  break;
2959
0
    case FcElementPlus:
2960
0
  FcParseBinary (parse, FcOpPlus);
2961
0
  break;
2962
0
    case FcElementMinus:
2963
0
  FcParseBinary (parse, FcOpMinus);
2964
0
  break;
2965
0
    case FcElementTimes:
2966
0
  FcParseBinary (parse, FcOpTimes);
2967
0
  break;
2968
0
    case FcElementDivide:
2969
0
  FcParseBinary (parse, FcOpDivide);
2970
0
  break;
2971
0
    case FcElementNot:
2972
0
  FcParseUnary (parse, FcOpNot);
2973
0
  break;
2974
0
    case FcElementIf:
2975
0
  FcParseBinary (parse, FcOpQuest);
2976
0
  break;
2977
0
    case FcElementFloor:
2978
0
  FcParseUnary (parse, FcOpFloor);
2979
0
  break;
2980
0
    case FcElementCeil:
2981
0
  FcParseUnary (parse, FcOpCeil);
2982
0
  break;
2983
0
    case FcElementRound:
2984
0
  FcParseUnary (parse, FcOpRound);
2985
0
  break;
2986
0
    case FcElementTrunc:
2987
0
  FcParseUnary (parse, FcOpTrunc);
2988
0
  break;
2989
0
    case FcElementUnknown:
2990
0
  break;
2991
312
    }
2992
312
    (void)FcPStackPop (parse);
2993
312
}
2994
2995
static void
2996
FcCharacterData (void *userData, const XML_Char *s, int len)
2997
208
{
2998
208
    FcConfigParse *parse = userData;
2999
3000
208
    if (!parse->pstack)
3001
0
  return;
3002
208
    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *)s, len))
3003
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
3004
208
}
3005
3006
static void
3007
FcStartDoctypeDecl (void           *userData,
3008
                    const XML_Char *doctypeName,
3009
                    const XML_Char *sysid FC_UNUSED,
3010
                    const XML_Char *pubid FC_UNUSED,
3011
                    int             has_internal_subset FC_UNUSED)
3012
0
{
3013
0
    FcConfigParse *parse = userData;
3014
3015
0
    if (strcmp ((char *)doctypeName, "fontconfig") != 0)
3016
0
  FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
3017
0
}
3018
3019
#ifdef ENABLE_LIBXML2
3020
3021
static void
3022
FcInternalSubsetDecl (void           *userData,
3023
                      const XML_Char *doctypeName,
3024
                      const XML_Char *sysid,
3025
                      const XML_Char *pubid)
3026
{
3027
    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3028
}
3029
3030
static void
3031
FcExternalSubsetDecl (void           *userData,
3032
                      const XML_Char *doctypeName,
3033
                      const XML_Char *sysid,
3034
                      const XML_Char *pubid)
3035
{
3036
    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3037
}
3038
3039
#else /* ENABLE_LIBXML2 */
3040
3041
static void
3042
FcEndDoctypeDecl (void *userData FC_UNUSED)
3043
0
{
3044
0
}
3045
3046
#endif /* ENABLE_LIBXML2 */
3047
3048
static int
3049
FcSortCmpStr (const void *a, const void *b)
3050
0
{
3051
0
    const FcChar8 *as = *((FcChar8 **)a);
3052
0
    const FcChar8 *bs = *((FcChar8 **)b);
3053
0
    return FcStrCmp (as, bs);
3054
0
}
3055
3056
static FcBool
3057
FcConfigParseAndLoadDir (FcConfig      *config,
3058
                         const FcChar8 *name,
3059
                         const FcChar8 *dir,
3060
                         FcBool         complain,
3061
                         FcBool         load)
3062
0
{
3063
0
    DIR           *d;
3064
0
    struct dirent *e;
3065
0
    FcBool         ret = FcTrue;
3066
0
    FcChar8       *file;
3067
0
    FcChar8       *base;
3068
0
    FcStrSet      *files;
3069
3070
0
    d = opendir ((char *)dir);
3071
0
    if (!d) {
3072
0
  if (complain)
3073
0
      FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3074
0
                       name);
3075
0
  ret = FcFalse;
3076
0
  goto bail0;
3077
0
    }
3078
    /* freed below */
3079
0
    file = (FcChar8 *)malloc (strlen ((char *)dir) + 1 + FC_MAX_FILE_LEN + 1);
3080
0
    if (!file) {
3081
0
  ret = FcFalse;
3082
0
  goto bail1;
3083
0
    }
3084
3085
0
    strcpy ((char *)file, (char *)dir);
3086
0
    strcat ((char *)file, "/");
3087
0
    base = file + strlen ((char *)file);
3088
3089
0
    files = FcStrSetCreateEx (FCSS_GROW_BY_64);
3090
0
    if (!files) {
3091
0
  ret = FcFalse;
3092
0
  goto bail2;
3093
0
    }
3094
3095
0
    if (FcDebug() & FC_DBG_CONFIG)
3096
0
  printf ("\tScanning config dir %s\n", dir);
3097
3098
0
    if (load)
3099
0
  FcConfigAddConfigDir (config, dir);
3100
3101
0
    while (ret && (e = readdir (d))) {
3102
0
  int d_len;
3103
0
#define TAIL     ".conf"
3104
0
#define TAIL_LEN 5
3105
  /*
3106
   * Add all files of the form [0-9]*.conf
3107
   */
3108
0
  d_len = strlen (e->d_name);
3109
0
  if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3110
0
      d_len > TAIL_LEN &&
3111
0
      strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) {
3112
0
      strcpy ((char *)base, (char *)e->d_name);
3113
0
      if (!FcStrSetAdd (files, file)) {
3114
0
    ret = FcFalse;
3115
0
    goto bail3;
3116
0
      }
3117
0
  }
3118
0
    }
3119
0
    if (ret && files->num > 0) {
3120
0
  int i;
3121
0
  qsort (files->strs, files->num, sizeof (FcChar8 *),
3122
0
         (int (*) (const void *, const void *))FcSortCmpStr);
3123
0
  for (i = 0; ret && i < files->num; i++)
3124
0
      ret = _FcConfigParse (config, files->strs[i], complain, load);
3125
0
    }
3126
0
bail3:
3127
0
    FcStrSetDestroy (files);
3128
0
bail2:
3129
0
    free (file);
3130
0
bail1:
3131
0
    closedir (d);
3132
0
bail0:
3133
0
    return ret || !complain;
3134
0
}
3135
3136
static FcBool
3137
FcConfigParseAndLoadFromMemoryInternal (FcConfig      *config,
3138
                                        const FcChar8 *filename,
3139
                                        const FcChar8 *buffer,
3140
                                        FcBool         complain,
3141
                                        FcBool         load)
3142
104
{
3143
104
    XML_Parser    p;
3144
104
    size_t        len;
3145
104
    FcConfigParse parse;
3146
104
    FcBool        error = FcTrue;
3147
104
    FcMatchKind   k;
3148
104
    FcPtrListIter liter;
3149
3150
#ifdef ENABLE_LIBXML2
3151
    xmlSAXHandler sax;
3152
#else
3153
104
    void          *buf;
3154
104
    const FcChar8 *s;
3155
104
    size_t         buflen;
3156
104
#endif
3157
3158
104
    FcInitDebug();
3159
3160
104
    if (!buffer)
3161
0
  return FcFalse;
3162
104
    len = strlen ((const char *)buffer);
3163
104
    if (FcDebug() & FC_DBG_CONFIG)
3164
0
  printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
3165
3166
#ifdef ENABLE_LIBXML2
3167
    memset (&sax, 0, sizeof (sax));
3168
3169
    sax.internalSubset = FcInternalSubsetDecl;
3170
    sax.externalSubset = FcExternalSubsetDecl;
3171
    sax.startElement = FcStartElement;
3172
    sax.endElement = FcEndElement;
3173
    sax.characters = FcCharacterData;
3174
3175
    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *)filename);
3176
#else
3177
104
    p = XML_ParserCreate ("UTF-8");
3178
104
#endif
3179
3180
104
    if (!p)
3181
0
  goto bail1;
3182
3183
104
    if (!FcConfigParseInit (&parse, filename, config, p, load))
3184
0
  goto bail2;
3185
3186
104
#ifndef ENABLE_LIBXML2
3187
3188
104
    XML_SetUserData (p, &parse);
3189
3190
104
    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3191
104
    XML_SetElementHandler (p, FcStartElement, FcEndElement);
3192
104
    XML_SetCharacterDataHandler (p, FcCharacterData);
3193
3194
104
#endif /* ENABLE_LIBXML2 */
3195
3196
104
#ifndef ENABLE_LIBXML2
3197
104
    s = buffer;
3198
208
    do {
3199
208
  buf = XML_GetBuffer (p, BUFSIZ);
3200
208
  if (!buf) {
3201
0
      FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3202
0
      goto bail3;
3203
0
  }
3204
208
  if (len > BUFSIZ) {
3205
0
      buflen = BUFSIZ;
3206
0
      len -= BUFSIZ;
3207
208
  } else {
3208
208
      buflen = len;
3209
208
      len = 0;
3210
208
  }
3211
208
  memcpy (buf, s, buflen);
3212
208
  s = s + buflen;
3213
208
#endif
3214
3215
#ifdef ENABLE_LIBXML2
3216
  if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
3217
#else
3218
208
    if (!XML_ParseBuffer (p, buflen, buflen == 0))
3219
0
#endif
3220
0
  {
3221
0
      FcConfigMessage (&parse, FcSevereError, "%s",
3222
0
                       XML_ErrorString (XML_GetErrorCode (p)));
3223
0
      goto bail3;
3224
0
  }
3225
208
#ifndef ENABLE_LIBXML2
3226
208
    } while (buflen != 0);
3227
104
#endif
3228
104
    error = parse.error;
3229
104
    if (load) {
3230
416
  for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) {
3231
312
      FcPtrListIter iter;
3232
3233
312
      FcPtrListIterInit (parse.ruleset->subst[k], &iter);
3234
312
      if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter)) {
3235
0
    FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
3236
0
    FcRuleSetReference (parse.ruleset);
3237
0
    FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
3238
0
      }
3239
312
  }
3240
104
    }
3241
104
    FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
3242
104
    FcRuleSetReference (parse.ruleset);
3243
104
    FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
3244
104
bail3:
3245
104
    FcConfigCleanup (&parse);
3246
104
bail2:
3247
104
    XML_ParserFree (p);
3248
104
bail1:
3249
104
    if (error && complain) {
3250
0
  FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
3251
0
  return FcFalse;
3252
0
    }
3253
104
    if (FcDebug() & FC_DBG_CONFIG)
3254
0
  printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
3255
104
    return FcTrue;
3256
104
}
3257
3258
static FcBool
3259
_FcConfigParse (FcConfig      *config,
3260
                const FcChar8 *name,
3261
                FcBool         complain,
3262
                FcBool         load)
3263
208
{
3264
208
    FcChar8 *filename = NULL, *realfilename = NULL;
3265
208
    int      fd;
3266
208
    int      len;
3267
208
    FcStrBuf sbuf;
3268
208
    char     buf[BUFSIZ];
3269
208
    FcBool   ret = FcFalse, complain_again = complain;
3270
208
    FcStrBuf reason;
3271
3272
208
    FcStrBufInit (&reason, NULL, 0);
3273
#ifdef _WIN32
3274
    _ensureWin32GettersReady();
3275
#endif
3276
3277
208
    filename = FcConfigGetFilename (config, name);
3278
208
    if (!filename) {
3279
104
  FcStrBufString (&reason, (FcChar8 *)"File not found");
3280
104
  if (name) {
3281
104
      FcStrBufString (&reason, (FcChar8 *)": ");
3282
104
      FcStrBufString (&reason, name);
3283
104
  } else {
3284
0
      FcChar8 *e = (FcChar8 *)getenv ("FONTCONFIG_FILE");
3285
0
      if (e) {
3286
0
    FcStrBufString (&reason, (FcChar8 *)": ");
3287
0
    FcStrBufString (&reason, e);
3288
0
      }
3289
0
  }
3290
104
  goto bail0;
3291
104
    }
3292
104
    realfilename = FcConfigRealFilename (config, name);
3293
104
    if (!realfilename) {
3294
0
  FcStrBufString (&reason, (FcChar8 *)"No such realfile: ");
3295
0
  FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3296
0
  goto bail0;
3297
0
    }
3298
104
    if (FcStrSetMember (config->availConfigFiles, realfilename)) {
3299
0
  FcStrFree (filename);
3300
0
  FcStrFree (realfilename);
3301
0
  return FcTrue;
3302
0
    }
3303
3304
104
    if (load) {
3305
104
  if (!FcStrSetAdd (config->configFiles, filename))
3306
0
      goto bail0;
3307
104
    }
3308
104
    if (!FcStrSetAdd (config->availConfigFiles, realfilename))
3309
0
  goto bail0;
3310
3311
104
    if (FcFileIsDir (realfilename)) {
3312
0
  ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
3313
0
  FcStrFree (filename);
3314
0
  FcStrFree (realfilename);
3315
0
  return ret;
3316
0
    }
3317
3318
104
    FcStrBufInit (&sbuf, NULL, 0);
3319
3320
104
    fd = FcOpen ((char *)realfilename, O_RDONLY);
3321
104
    if (fd == -1) {
3322
0
  FcStrBufString (&reason, (FcChar8 *)"Unable to open ");
3323
0
  FcStrBufString (&reason, realfilename);
3324
0
  goto bail1;
3325
0
    }
3326
3327
208
    do {
3328
208
  len = read (fd, buf, BUFSIZ);
3329
208
  if (len < 0) {
3330
0
      int  errno_ = errno;
3331
0
      char ebuf[BUFSIZ + 1];
3332
3333
0
#if HAVE_STRERROR_R
3334
0
      strerror_r (errno_, ebuf, BUFSIZ);
3335
#elif HAVE_STRERROR
3336
      char  *tmp = strerror (errno_);
3337
      size_t len = strlen (tmp);
3338
      memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
3339
      ebuf[FC_MIN (BUFSIZ, len)] = 0;
3340
#else
3341
      ebuf[0] = 0;
3342
#endif
3343
0
      FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
3344
0
      close (fd);
3345
0
      goto bail1;
3346
0
  }
3347
208
  FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
3348
208
    } while (len != 0);
3349
104
    close (fd);
3350
3351
104
    ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
3352
104
    complain_again = FcFalse; /* no need to reclaim here */
3353
104
bail1:
3354
104
    FcStrBufDestroy (&sbuf);
3355
208
bail0:
3356
208
    if (filename)
3357
104
  FcStrFree (filename);
3358
208
    if (realfilename)
3359
104
  FcStrFree (realfilename);
3360
208
    if (!complain) {
3361
104
  FcStrBufDestroy (&reason);
3362
104
  return FcTrue;
3363
104
    }
3364
104
    if (!ret && complain_again) {
3365
0
  if (name)
3366
0
      FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason));
3367
0
  else
3368
0
      FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason));
3369
0
  FcStrBufDestroy (&reason);
3370
0
  return FcFalse;
3371
0
    }
3372
104
    FcStrBufDestroy (&reason);
3373
104
    return ret;
3374
104
}
3375
3376
FcBool
3377
FcConfigParseOnly (FcConfig      *config,
3378
                   const FcChar8 *name,
3379
                   FcBool         complain)
3380
104
{
3381
104
    return _FcConfigParse (config, name, complain, FcFalse);
3382
104
}
3383
3384
FcBool
3385
FcConfigParseAndLoad (FcConfig      *config,
3386
                      const FcChar8 *name,
3387
                      FcBool         complain)
3388
104
{
3389
104
    return _FcConfigParse (config, name, complain, FcTrue);
3390
104
}
3391
3392
FcBool
3393
FcConfigParseAndLoadFromMemory (FcConfig      *config,
3394
                                const FcChar8 *buffer,
3395
                                FcBool         complain)
3396
0
{
3397
0
    return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
3398
0
}
3399
3400
#ifdef _WIN32
3401
static void
3402
_ensureWin32GettersReady ()
3403
{
3404
    if (!pGetSystemWindowsDirectory) {
3405
  HMODULE hk32 = GetModuleHandleA ("kernel32.dll");
3406
  if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetProcAddress (hk32, "GetSystemWindowsDirectoryA")))
3407
      pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetWindowsDirectory;
3408
    }
3409
    if (!pSHGetFolderPathA) {
3410
  HMODULE hSh = LoadLibraryA ("shfolder.dll");
3411
  /* the check is done later, because there is no provided fallback */
3412
  if (hSh)
3413
      pSHGetFolderPathA = (pfnSHGetFolderPathA)GetProcAddress (hSh, "SHGetFolderPathA");
3414
    }
3415
}
3416
#endif  // _WIN32
3417
3418
#define __fcxml__
3419
#include "fcaliastail.h"
3420
#undef __fcxml__