Coverage Report

Created: 2026-02-10 07:39

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