1 /*
2  * fontconfig/src/fcname.c
3  *
4  * Copyright © 2000 Keith Packard
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of the author(s) not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  The authors make no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24 
25 #include "fcint.h"
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 
31 static const FcObjectType FcObjects[] = {
32 #define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME, Type },
33 #include "fcobjs.h"
34 #undef FC_OBJECT
35 };
36 
37 #define NUM_OBJECT_TYPES ((int) (sizeof FcObjects / sizeof FcObjects[0]))
38 
39 static const FcObjectType *
FcObjectFindById(FcObject object)40 FcObjectFindById (FcObject object)
41 {
42     if (1 <= object && object <= NUM_OBJECT_TYPES)
43 	return &FcObjects[object - 1];
44     return FcObjectLookupOtherTypeById (object);
45 }
46 
47 FcBool
FcNameRegisterObjectTypes(const FcObjectType * types,int ntypes)48 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
49 {
50     /* Deprecated. */
51     return FcFalse;
52 }
53 
54 FcBool
FcNameUnregisterObjectTypes(const FcObjectType * types,int ntypes)55 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
56 {
57     /* Deprecated. */
58     return FcFalse;
59 }
60 
61 const FcObjectType *
FcNameGetObjectType(const char * object)62 FcNameGetObjectType (const char *object)
63 {
64     int id = FcObjectLookupBuiltinIdByName (object);
65 
66     if (!id)
67 	return FcObjectLookupOtherTypeByName (object);
68 
69     return &FcObjects[id - 1];
70 }
71 
72 FcBool
FcObjectValidType(FcObject object,FcType type)73 FcObjectValidType (FcObject object, FcType type)
74 {
75     const FcObjectType    *t = FcObjectFindById (object);
76 
77     if (t) {
78 	switch ((int) t->type) {
79 	case FcTypeUnknown:
80 	    return FcTrue;
81 	case FcTypeDouble:
82 	case FcTypeInteger:
83 	    if (type == FcTypeDouble || type == FcTypeInteger)
84 		return FcTrue;
85 	    break;
86 	case FcTypeLangSet:
87 	    if (type == FcTypeLangSet || type == FcTypeString)
88 		return FcTrue;
89 	    break;
90 	default:
91 	    if (type == t->type)
92 		return FcTrue;
93 	    break;
94 	}
95 	return FcFalse;
96     }
97     return FcTrue;
98 }
99 
100 FcObject
FcObjectFromName(const char * name)101 FcObjectFromName (const char * name)
102 {
103     return FcObjectLookupIdByName (name);
104 }
105 
106 FcObjectSet *
FcObjectGetSet(void)107 FcObjectGetSet (void)
108 {
109     int		i;
110     FcObjectSet	*os = NULL;
111 
112 
113     os = FcObjectSetCreate ();
114     for (i = 0; i < NUM_OBJECT_TYPES; i++)
115 	FcObjectSetAdd (os, FcObjects[i].object);
116 
117     return os;
118 }
119 
120 const char *
FcObjectName(FcObject object)121 FcObjectName (FcObject object)
122 {
123     const FcObjectType   *o = FcObjectFindById (object);
124 
125     if (o)
126 	return o->object;
127 
128     return FcObjectLookupOtherNameById (object);
129 }
130 
131 static const FcConstant _FcBaseConstants[] = {
132     { (FcChar8 *) "thin",	    "weight",   FC_WEIGHT_THIN, },
133     { (FcChar8 *) "extralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
134     { (FcChar8 *) "ultralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
135     { (FcChar8 *) "light",	    "weight",   FC_WEIGHT_LIGHT, },
136     { (FcChar8 *) "book",	    "weight",	FC_WEIGHT_BOOK, },
137     { (FcChar8 *) "regular",	    "weight",   FC_WEIGHT_REGULAR, },
138     { (FcChar8 *) "medium",	    "weight",   FC_WEIGHT_MEDIUM, },
139     { (FcChar8 *) "demibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
140     { (FcChar8 *) "semibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
141     { (FcChar8 *) "bold",	    "weight",   FC_WEIGHT_BOLD, },
142     { (FcChar8 *) "extrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
143     { (FcChar8 *) "ultrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
144     { (FcChar8 *) "black",	    "weight",   FC_WEIGHT_BLACK, },
145     { (FcChar8 *) "heavy",	    "weight",	FC_WEIGHT_HEAVY, },
146 
147     { (FcChar8 *) "roman",	    "slant",    FC_SLANT_ROMAN, },
148     { (FcChar8 *) "italic",	    "slant",    FC_SLANT_ITALIC, },
149     { (FcChar8 *) "oblique",	    "slant",    FC_SLANT_OBLIQUE, },
150 
151     { (FcChar8 *) "ultracondensed", "width",	FC_WIDTH_ULTRACONDENSED },
152     { (FcChar8 *) "extracondensed", "width",	FC_WIDTH_EXTRACONDENSED },
153     { (FcChar8 *) "condensed",	    "width",	FC_WIDTH_CONDENSED },
154     { (FcChar8 *) "semicondensed",  "width",	FC_WIDTH_SEMICONDENSED },
155     { (FcChar8 *) "normal",	    "width",	FC_WIDTH_NORMAL },
156     { (FcChar8 *) "semiexpanded",   "width",	FC_WIDTH_SEMIEXPANDED },
157     { (FcChar8 *) "expanded",	    "width",	FC_WIDTH_EXPANDED },
158     { (FcChar8 *) "extraexpanded",  "width",	FC_WIDTH_EXTRAEXPANDED },
159     { (FcChar8 *) "ultraexpanded",  "width",	FC_WIDTH_ULTRAEXPANDED },
160 
161     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
162     { (FcChar8 *) "dual",	    "spacing",  FC_DUAL, },
163     { (FcChar8 *) "mono",	    "spacing",  FC_MONO, },
164     { (FcChar8 *) "charcell",	    "spacing",  FC_CHARCELL, },
165 
166     { (FcChar8 *) "unknown",	    "rgba",	    FC_RGBA_UNKNOWN },
167     { (FcChar8 *) "rgb",	    "rgba",	    FC_RGBA_RGB, },
168     { (FcChar8 *) "bgr",	    "rgba",	    FC_RGBA_BGR, },
169     { (FcChar8 *) "vrgb",	    "rgba",	    FC_RGBA_VRGB },
170     { (FcChar8 *) "vbgr",	    "rgba",	    FC_RGBA_VBGR },
171     { (FcChar8 *) "none",	    "rgba",	    FC_RGBA_NONE },
172 
173     { (FcChar8 *) "hintnone",	    "hintstyle",   FC_HINT_NONE },
174     { (FcChar8 *) "hintslight",	    "hintstyle",   FC_HINT_SLIGHT },
175     { (FcChar8 *) "hintmedium",	    "hintstyle",   FC_HINT_MEDIUM },
176     { (FcChar8 *) "hintfull",	    "hintstyle",   FC_HINT_FULL },
177 
178     { (FcChar8 *) "antialias",	    "antialias",    FcTrue },
179     { (FcChar8 *) "hinting",	    "hinting",	    FcTrue },
180     { (FcChar8 *) "verticallayout", "verticallayout",	FcTrue },
181     { (FcChar8 *) "autohint",	    "autohint",	    FcTrue },
182     { (FcChar8 *) "globaladvance",  "globaladvance",	FcTrue }, /* deprecated */
183     { (FcChar8 *) "outline",	    "outline",	    FcTrue },
184     { (FcChar8 *) "scalable",	    "scalable",	    FcTrue },
185     { (FcChar8 *) "minspace",	    "minspace",	    FcTrue },
186     { (FcChar8 *) "embolden",	    "embolden",	    FcTrue },
187     { (FcChar8 *) "embeddedbitmap", "embeddedbitmap",	FcTrue },
188     { (FcChar8 *) "decorative",	    "decorative",   FcTrue },
189     { (FcChar8 *) "lcdnone",	    "lcdfilter",    FC_LCD_NONE },
190     { (FcChar8 *) "lcddefault",	    "lcdfilter",    FC_LCD_DEFAULT },
191     { (FcChar8 *) "lcdlight",	    "lcdfilter",    FC_LCD_LIGHT },
192     { (FcChar8 *) "lcdlegacy",	    "lcdfilter",    FC_LCD_LEGACY },
193 };
194 
195 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
196 
197 FcBool
FcNameRegisterConstants(const FcConstant * consts,int nconsts)198 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
199 {
200     /* Deprecated. */
201     return FcFalse;
202 }
203 
204 FcBool
FcNameUnregisterConstants(const FcConstant * consts,int nconsts)205 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
206 {
207     /* Deprecated. */
208     return FcFalse;
209 }
210 
211 const FcConstant *
FcNameGetConstant(const FcChar8 * string)212 FcNameGetConstant (const FcChar8 *string)
213 {
214     unsigned int	    i;
215 
216     for (i = 0; i < NUM_FC_CONSTANTS; i++)
217 	if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name))
218 	    return &_FcBaseConstants[i];
219 
220     return 0;
221 }
222 
223 FcBool
FcNameConstant(const FcChar8 * string,int * result)224 FcNameConstant (const FcChar8 *string, int *result)
225 {
226     const FcConstant	*c;
227 
228     if ((c = FcNameGetConstant(string)))
229     {
230 	*result = c->value;
231 	return FcTrue;
232     }
233     return FcFalse;
234 }
235 
236 FcBool
FcNameBool(const FcChar8 * v,FcBool * result)237 FcNameBool (const FcChar8 *v, FcBool *result)
238 {
239     char    c0, c1;
240 
241     c0 = *v;
242     c0 = FcToLower (c0);
243     if (c0 == 't' || c0 == 'y' || c0 == '1')
244     {
245 	*result = FcTrue;
246 	return FcTrue;
247     }
248     if (c0 == 'f' || c0 == 'n' || c0 == '0')
249     {
250 	*result = FcFalse;
251 	return FcTrue;
252     }
253     if (c0 == 'o')
254     {
255 	c1 = v[1];
256 	c1 = FcToLower (c1);
257 	if (c1 == 'n')
258 	{
259 	    *result = FcTrue;
260 	    return FcTrue;
261 	}
262 	if (c1 == 'f')
263 	{
264 	    *result = FcFalse;
265 	    return FcTrue;
266 	}
267     }
268     return FcFalse;
269 }
270 
271 static FcValue
FcNameConvert(FcType type,FcChar8 * string)272 FcNameConvert (FcType type, FcChar8 *string)
273 {
274     FcValue	v;
275     FcMatrix	m;
276 
277     v.type = type;
278     switch ((int) v.type) {
279     case FcTypeInteger:
280 	if (!FcNameConstant (string, &v.u.i))
281 	    v.u.i = atoi ((char *) string);
282 	break;
283     case FcTypeString:
284 	v.u.s = FcStrdup (string);
285 	if (!v.u.s)
286 	    v.type = FcTypeVoid;
287 	break;
288     case FcTypeBool:
289 	if (!FcNameBool (string, &v.u.b))
290 	    v.u.b = FcFalse;
291 	break;
292     case FcTypeDouble:
293 	v.u.d = strtod ((char *) string, 0);
294 	break;
295     case FcTypeMatrix:
296 	FcMatrixInit (&m);
297 	sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy);
298 	v.u.m = FcMatrixCopy (&m);
299 	break;
300     case FcTypeCharSet:
301 	v.u.c = FcNameParseCharSet (string);
302 	if (!v.u.c)
303 	    v.type = FcTypeVoid;
304 	break;
305     case FcTypeLangSet:
306 	v.u.l = FcNameParseLangSet (string);
307 	if (!v.u.l)
308 	    v.type = FcTypeVoid;
309 	break;
310     default:
311 	break;
312     }
313     return v;
314 }
315 
316 static const FcChar8 *
FcNameFindNext(const FcChar8 * cur,const char * delim,FcChar8 * save,FcChar8 * last)317 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
318 {
319     FcChar8    c;
320 
321     while ((c = *cur))
322     {
323 	if (!isspace (c))
324 	    break;
325 	++cur;
326     }
327     while ((c = *cur))
328     {
329 	if (c == '\\')
330 	{
331 	    ++cur;
332 	    if (!(c = *cur))
333 		break;
334 	}
335 	else if (strchr (delim, c))
336 	    break;
337 	++cur;
338 	*save++ = c;
339     }
340     *save = 0;
341     *last = *cur;
342     if (*cur)
343 	cur++;
344     return cur;
345 }
346 
347 FcPattern *
FcNameParse(const FcChar8 * name)348 FcNameParse (const FcChar8 *name)
349 {
350     FcChar8		*save;
351     FcPattern		*pat;
352     double		d;
353     FcChar8		*e;
354     FcChar8		delim;
355     FcValue		v;
356     const FcObjectType	*t;
357     const FcConstant	*c;
358 
359     /* freed below */
360     save = malloc (strlen ((char *) name) + 1);
361     if (!save)
362 	goto bail0;
363     pat = FcPatternCreate ();
364     if (!pat)
365 	goto bail1;
366 
367     for (;;)
368     {
369 	name = FcNameFindNext (name, "-,:", save, &delim);
370 	if (save[0])
371 	{
372 	    if (!FcPatternAddString (pat, FC_FAMILY, save))
373 		goto bail2;
374 	}
375 	if (delim != ',')
376 	    break;
377     }
378     if (delim == '-')
379     {
380 	for (;;)
381 	{
382 	    name = FcNameFindNext (name, "-,:", save, &delim);
383 	    d = strtod ((char *) save, (char **) &e);
384 	    if (e != save)
385 	    {
386 		if (!FcPatternAddDouble (pat, FC_SIZE, d))
387 		    goto bail2;
388 	    }
389 	    if (delim != ',')
390 		break;
391 	}
392     }
393     while (delim == ':')
394     {
395 	name = FcNameFindNext (name, "=_:", save, &delim);
396 	if (save[0])
397 	{
398 	    if (delim == '=' || delim == '_')
399 	    {
400 		t = FcNameGetObjectType ((char *) save);
401 		for (;;)
402 		{
403 		    name = FcNameFindNext (name, ":,", save, &delim);
404 		    if (t)
405 		    {
406 			v = FcNameConvert (t->type, save);
407 			if (!FcPatternAdd (pat, t->object, v, FcTrue))
408 			{
409 			    FcValueDestroy (v);
410 			    goto bail2;
411 			}
412 			FcValueDestroy (v);
413 		    }
414 		    if (delim != ',')
415 			break;
416 		}
417 	    }
418 	    else
419 	    {
420 		if ((c = FcNameGetConstant (save)))
421 		{
422 		    t = FcNameGetObjectType ((char *) c->object);
423 		    if (t == NULL)
424 			goto bail2;
425 		    switch ((int) t->type) {
426 		    case FcTypeInteger:
427 		    case FcTypeDouble:
428 			if (!FcPatternAddInteger (pat, c->object, c->value))
429 			    goto bail2;
430 			break;
431 		    case FcTypeBool:
432 			if (!FcPatternAddBool (pat, c->object, c->value))
433 			    goto bail2;
434 			break;
435 		    default:
436 			break;
437 		    }
438 		}
439 	    }
440 	}
441     }
442 
443     free (save);
444     return pat;
445 
446 bail2:
447     FcPatternDestroy (pat);
448 bail1:
449     free (save);
450 bail0:
451     return 0;
452 }
453 static FcBool
FcNameUnparseString(FcStrBuf * buf,const FcChar8 * string,const FcChar8 * escape)454 FcNameUnparseString (FcStrBuf	    *buf,
455 		     const FcChar8  *string,
456 		     const FcChar8  *escape)
457 {
458     FcChar8 c;
459     while ((c = *string++))
460     {
461 	if (escape && strchr ((char *) escape, (char) c))
462 	{
463 	    if (!FcStrBufChar (buf, escape[0]))
464 		return FcFalse;
465 	}
466 	if (!FcStrBufChar (buf, c))
467 	    return FcFalse;
468     }
469     return FcTrue;
470 }
471 
472 FcBool
FcNameUnparseValue(FcStrBuf * buf,FcValue * v0,FcChar8 * escape)473 FcNameUnparseValue (FcStrBuf	*buf,
474 		    FcValue	*v0,
475 		    FcChar8	*escape)
476 {
477     FcChar8	temp[1024];
478     FcValue v = FcValueCanonicalize(v0);
479 
480     switch (v.type) {
481     case FcTypeUnknown:
482     case FcTypeVoid:
483 	return FcTrue;
484     case FcTypeInteger:
485 	sprintf ((char *) temp, "%d", v.u.i);
486 	return FcNameUnparseString (buf, temp, 0);
487     case FcTypeDouble:
488 	sprintf ((char *) temp, "%g", v.u.d);
489 	return FcNameUnparseString (buf, temp, 0);
490     case FcTypeString:
491 	return FcNameUnparseString (buf, v.u.s, escape);
492     case FcTypeBool:
493 	return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
494     case FcTypeMatrix:
495 	sprintf ((char *) temp, "%g %g %g %g",
496 		 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
497 	return FcNameUnparseString (buf, temp, 0);
498     case FcTypeCharSet:
499 	return FcNameUnparseCharSet (buf, v.u.c);
500     case FcTypeLangSet:
501 	return FcNameUnparseLangSet (buf, v.u.l);
502     case FcTypeFTFace:
503 	return FcTrue;
504     }
505     return FcFalse;
506 }
507 
508 FcBool
FcNameUnparseValueList(FcStrBuf * buf,FcValueListPtr v,FcChar8 * escape)509 FcNameUnparseValueList (FcStrBuf	*buf,
510 			FcValueListPtr	v,
511 			FcChar8		*escape)
512 {
513     while (v)
514     {
515 	if (!FcNameUnparseValue (buf, &v->value, escape))
516 	    return FcFalse;
517 	if ((v = FcValueListNext(v)) != NULL)
518 	    if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
519 		return FcFalse;
520     }
521     return FcTrue;
522 }
523 
524 #define FC_ESCAPE_FIXED    "\\-:,"
525 #define FC_ESCAPE_VARIABLE "\\=_:,"
526 
527 FcChar8 *
FcNameUnparse(FcPattern * pat)528 FcNameUnparse (FcPattern *pat)
529 {
530     return FcNameUnparseEscaped (pat, FcTrue);
531 }
532 
533 FcChar8 *
FcNameUnparseEscaped(FcPattern * pat,FcBool escape)534 FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
535 {
536     FcStrBuf		    buf;
537     FcChar8		    buf_static[8192];
538     int			    i;
539     FcPatternElt	    *e;
540 
541     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
542     e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
543     if (e)
544     {
545         if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
546 	    goto bail0;
547     }
548     e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
549     if (e)
550     {
551 	if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
552 	    goto bail0;
553 	if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
554 	    goto bail0;
555     }
556     for (i = 0; i < NUM_OBJECT_TYPES; i++)
557     {
558 	FcObject id = i + 1;
559 	const FcObjectType	    *o;
560 	o = &FcObjects[i];
561 	if (!strcmp (o->object, FC_FAMILY) ||
562 	    !strcmp (o->object, FC_SIZE))
563 	    continue;
564 
565 	e = FcPatternObjectFindElt (pat, id);
566 	if (e)
567 	{
568 	    if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
569 		goto bail0;
570 	    if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
571 		goto bail0;
572 	    if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
573 		goto bail0;
574 	    if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
575 					 (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
576 		goto bail0;
577 	}
578     }
579     return FcStrBufDone (&buf);
580 bail0:
581     FcStrBufDestroy (&buf);
582     return 0;
583 }
584 #define __fcname__
585 #include "fcaliastail.h"
586 #undef __fcname__
587