/* See LICENSE file for copyright and license details. */ #include "libfonts.h" #include #include #include #include #include #include #include #define LIST_FIELDS_EXCEPT_FINAL(X)\ X(foundry)\ X(family_name)\ X(weight_name)\ X(slant)\ X(setwidth_name)\ X(add_style_name)\ X(pixel_size)\ X(point_size)\ X(resolution_x)\ X(resolution_y)\ X(spacing)\ X(average_width)\ X(charset_registry) struct range { uint32_t first; uint32_t last; }; static int parse_hexadecimal(const char *s, const char **endp, uint32_t *valuep) { uint64_t r = 0; if (!isxdigit(*s)) return -1; for (;; s++) { if (isdigit(*s)) r = (r * 16) | (*s & 15); else if (isxdigit(*s)) r = (r * 16) | ((*s & 15) + 9); else break; if (r > INT32_MAX) return -1; } *endp = s; *valuep = (uint32_t)r; return 0; } static int parse_decimal(const char *s, const char **endp, uint32_t *valuep) { uint64_t r = 0; if (!isdigit(*s)) return -1; for (; isdigit(*s); s++) { r = r * 10 + (*s & 15); if (r > INT32_MAX) return -1; } *endp = s; *valuep = (uint32_t)r; return 0; } static int parse_number(const char *s, const char **endp, uint32_t *valuep) { if (s[0] == '0' && s[1] == 'x') return parse_hexadecimal(&s[2], endp, valuep); else return parse_decimal(&s[0], endp, valuep); } static int cmprange(const void *av, const void *bv) { const struct range *a = av, *b = bv; return a->first < b->first ? -1 : a->first > b->first; } static int fix_charset_subset(char *out, const char *in) { struct range ranges[128], saved; size_t i, n = 0; const char *s; uint32_t t; for (s = in; *s; s++) { if (*s == ' ') continue; if (parse_number(s, &s, &ranges[0].first)) return -1; if (*s == '_') { if (parse_number(&s[1], &s, &ranges[0].last)) return -1; if (ranges[0].first > ranges[0].last) { t = ranges[0].first; ranges[0].first = ranges[0].last; ranges[0].last = t; } } else { ranges[0].last = ranges[0].first; } if (*s && *s != ' ') return -1; } if (!n) { *out = '\0'; return 0; } qsort(ranges, n, sizeof(*ranges), cmprange); saved = ranges[0]; for (i = 1; i < n; i++) { if (ranges[i].first <= saved.last) { saved.last = ranges[i].last; } else { if (saved.first == saved.last) out += sprintf(out, "%"PRId32" ", saved.first); else out += sprintf(out, "%"PRId32"-%"PRId32" ", saved.first, saved.last); saved = ranges[i]; } } if (saved.first == saved.last) out += sprintf(out, "%"PRId32" ", saved.first); else out += sprintf(out, "%"PRId32"-%"PRId32" ", saved.first, saved.last); out[-1] = '\0'; return 0; } int libfonts_decode_font_description(struct libfonts_font_description *desc, const char *in) { char subset[256]; const char *s = in; char *buf, *ss = subset; int have_subset = 0; int in_subset = 0; if (strlen(in) > 255) { errno = EINVAL; return -1; } memset(desc, 0, sizeof(*desc)); buf = desc->_buf; if (*s == '+') { desc->xlfd_version = buf; for (s++; *s && *s != '-'; s++) *buf++ = *s == '~' ? '-' : *s; *buf++ = '\0'; } #define X(F)\ if (*s != '-')\ goto private;\ desc->F = buf;\ for (s++; *s && *s != '-'; s++)\ *buf++ = *s == '~' ? '-' : *s;\ *buf++ = '\0'; LIST_FIELDS_EXCEPT_FINAL(X) #undef X if (*s != '-') goto private; desc->charset_encoding = buf; for (s++; *s && *s != '-'; s++) { if (in_subset) { if (*s == ']') in_subset = 0; else *ss++ = *s == '~' ? '-' : *s; } else { if (*s == '[') { in_subset = 1; if (have_subset) *ss++ = ' '; else have_subset = 1; } else { *buf++ = *s == '~' ? '-' : *s; } } } *buf++ = '\0'; if (in_subset) goto private; if (have_subset) { *ss = '\0'; desc->charset_subset = buf; if (fix_charset_subset(buf, subset)) goto private; } if (*s == '-') { desc->unrecognised_fields = buf; stpcpy(buf, &s[1]); } return 0; private: memset(desc, 0, sizeof(*desc)); stpcpy(desc->_buf, in); desc->private_font_name = desc->_buf; return 0; }