aboutsummaryrefslogtreecommitdiffstats
path: root/libfonts_parse_encoding_line.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfonts_parse_encoding_line.c')
-rw-r--r--libfonts_parse_encoding_line.c439
1 files changed, 439 insertions, 0 deletions
diff --git a/libfonts_parse_encoding_line.c b/libfonts_parse_encoding_line.c
new file mode 100644
index 0000000..a4d876b
--- /dev/null
+++ b/libfonts_parse_encoding_line.c
@@ -0,0 +1,439 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+#define LEVEL_MASK 0x0003
+#define ENCODING_LEVEL 1
+#define MAPPING_LEVEL 2
+#define MAX_LEVEL MAPPING_LEVEL
+#define HAVE_SIZE_BIT 0x4000
+#define HAVE_FIRST_INDEX_BIT 0x2000
+#define HAVE_FIRST_INDEX_BYTE_2_BIT 0x1000
+#define HAVE_BITS (HAVE_SIZE_BIT | HAVE_FIRST_INDEX_BIT | HAVE_FIRST_INDEX_BYTE_2_BIT)
+
+enum keyword {
+ NO_KEYWORD,
+ STARTENCODING,
+ ENDENCODING,
+ ALIAS,
+ SIZE,
+ FIRSTINDEX,
+ STARTMAPPING,
+ ENDMAPPING,
+ UNDEFINE
+};
+
+static char *
+get_string(const char *s, const char **endp)
+{
+ size_t len;
+ const char *p;
+ char *r;
+ char *ret;
+
+ for (len = 1, p = &s[1]; *p && *p != '\n' && *p != '#'; p++)
+ len += (!isblank(*p) || isblank(p[-1]));
+
+ ret = malloc(len + 1);
+ if (!ret)
+ return NULL;
+
+ r = ret;
+ for (*r++ = *s++; *s && *s != '\n' && *s != '#'; s++) {
+ if (!isblank(*s))
+ *r++ = *s;
+ else if (isblank(s[-1]))
+ *r++ = ' ';
+ }
+ *r = '\0';
+ return ret;
+}
+
+static int
+get_uints(uintmax_t *u1p, uintmax_t *u2p, uintmax_t *u3p, uintmax_t max,
+ const char *s, const char **endp, struct libfonts_context *ctx)
+{
+ int r = 0;
+ uintmax_t u, *up, digit;
+
+ while (r < INT_MAX && isdigit(*s)) {
+ u = 0;
+ do {
+ digit = (uintmax_t)(*s & 15);
+ if (u > (max - digit) / 10) {
+ u = max;
+ while (isdigit(*++s));
+ /* TODO warning */
+ break;
+ }
+ u = u * 10 + digit;
+ } while (isdigit(*++s));
+
+ up = (r == 0 ? u1p :
+ r == 1 ? u2p :
+ r == 2 ? u3p : NULL);
+ if (up)
+ *up = u;
+ r += 1;
+
+ if (!*s || *s == '\n' || *s == '#')
+ break;
+ while (isblank(*s))
+ s++;
+ }
+
+ *endp = s;
+ return r;
+}
+
+int
+libfonts_parse_encoding_line(struct libfonts_encoding **encodingp, int *statep,
+ const char *line, char **endp, struct libfonts_context *ctx)
+{
+ int ret = 0, r;
+ size_t keyword_len;
+ uintmax_t ju1, ju2, ju3;
+ enum keyword keyword;
+ struct libfonts_encoding_mapping *mapping;
+ void *new;
+
+ if (!encodingp ||
+ !statep ||
+ !line ||
+ (*statep & LEVEL_MASK) > MAX_LEVEL ||
+ ((*statep & LEVEL_MASK) ? (*statep & ~(LEVEL_MASK | HAVE_BITS)) : *statep) ||
+ (*statep && !*encodingp) ||
+ ((*statep & LEVEL_MASK) == MAPPING_LEVEL && !(*encodingp)->nmappings) ||
+ (*encodingp && ((!(*encodingp)->aliases && (*encodingp)->naliases) ||
+ (!(*encodingp)->mappings && (*encodingp)->nmappings) ||
+ (*encodingp)->size_rows > 0x100 ||
+ (*encodingp)->size_cols > 0x100))) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ while (isblank(*line))
+ line++;
+
+ if (!*line || *line == '#')
+ goto out;
+
+ if (!strncasecmp(line, "STARTENCODING", keyword_len = sizeof("STARTENCODING") - 1))
+ keyword = STARTENCODING;
+ else if (!strncasecmp(line, "ENDENCODING", keyword_len = sizeof("ENDENCODING") - 1))
+ keyword = ENDENCODING;
+ else if (!strncasecmp(line, "ALIAS", keyword_len = sizeof("ALIAS") - 1))
+ keyword = ALIAS;
+ else if (!strncasecmp(line, "SIZE", keyword_len = sizeof("SIZE") - 1))
+ keyword = SIZE;
+ else if (!strncasecmp(line, "FIRSTINDEX", keyword_len = sizeof("FIRSTINDEX") - 1))
+ keyword = FIRSTINDEX;
+ else if (!strncasecmp(line, "STARTMAPPING", keyword_len = sizeof("STARTMAPPING") - 1))
+ keyword = STARTMAPPING;
+ else if (!strncasecmp(line, "ENDMAPPING", keyword_len = sizeof("ENDMAPPING") - 1))
+ keyword = ENDMAPPING;
+ else if (!strncasecmp(line, "UNDEFINE", keyword_len = sizeof("UNDEFINE") - 1))
+ keyword = UNDEFINE;
+ else if (!isdigit(*line))
+ goto bad_keyword;
+ else
+ keyword = NO_KEYWORD;
+
+ if (keyword != NO_KEYWORD) {
+ if (line[keyword_len] && !isblank(line[keyword_len])) {
+ /* TODO warning */
+ goto out;
+ }
+ line = &line[keyword_len];
+ while (isblank(*line))
+ line++;
+ }
+
+ switch (keyword) {
+ case STARTENCODING:
+ if (*statep != 0) {
+ /* TODO warning */
+ break;
+ }
+ if (!*encodingp) {
+ *encodingp = calloc(1, sizeof(**encodingp));
+ if (!*encodingp)
+ goto enomem;
+ }
+ (*encodingp)->size_rows = 256;
+ (*encodingp)->name = get_string(line, &line);
+ if (!(*encodingp)->name)
+ goto enomem;
+ if (!*(*encodingp)->name) {
+ /* TODO warning */
+ }
+ *statep = ENCODING_LEVEL;
+ break;
+
+ case ENDENCODING:
+ if ((*statep & LEVEL_MASK) == MAPPING_LEVEL) {
+ /* TODO warning */
+ } else if ((*statep & LEVEL_MASK) != ENCODING_LEVEL) {
+ /* TODO warning */
+ break;
+ }
+ if (*line && *line != '\n' && *line != '#') {
+ /* TODO warning */
+ }
+ if ((*statep & HAVE_FIRST_INDEX_BYTE_2_BIT) && (*encodingp)->size_cols) {
+ /* TODO warning */
+ (*encodingp)->first_index_col = 0;
+ }
+ ret = 1;
+ *statep = 0;
+ break;
+
+ case ALIAS:
+ if ((*statep & LEVEL_MASK) != ENCODING_LEVEL) {
+ /* TODO warning */
+ break;
+ }
+ if ((*encodingp)->naliases > SIZE_MAX / sizeof(*(*encodingp)->aliases) - 1)
+ goto enomem;
+ new = realloc((*encodingp)->aliases, ((*encodingp)->naliases + 1) * sizeof(*(*encodingp)->aliases));
+ if (!new)
+ goto enomem;
+ (*encodingp)->aliases = new;
+ (*encodingp)->aliases[(*encodingp)->naliases] = get_string(line, &line);
+ if (!(*encodingp)->aliases[(*encodingp)->naliases])
+ goto enomem;
+ if (!*(*encodingp)->aliases[(*encodingp)->naliases]) {
+ /* TODO warning */
+ }
+ (*encodingp)->naliases += 1;
+ break;
+
+ case SIZE:
+ if ((*statep & LEVEL_MASK) != ENCODING_LEVEL) {
+ /* TODO warning */
+ break;
+ } else if (*statep & HAVE_SIZE_BIT) {
+ /* TODO warning */
+ }
+ ju2 = 0;
+ r = get_uints(&ju1, &ju2, NULL, 0x100, line, &line, ctx);
+ if (r < 0) {
+ goto fail;
+ } else if (r == 0) {
+ /* TODO warning */
+ break;
+ } else if (r > 2) {
+ /* TODO warning */
+ break;
+ } else if (*line && *line != '\n' && *line != '#') {
+ /* TODO warning */
+ break;
+ }
+ if (!ju1) {
+ /* TODO warning */
+ break;
+ }
+ if (r > 1 && !ju2) {
+ /* TODO warning */
+ break;
+ }
+ (*encodingp)->size_rows = (uint16_t)ju1;
+ (*encodingp)->size_cols = (uint16_t)ju2;
+ *statep |= HAVE_SIZE_BIT;
+ break;
+
+ case FIRSTINDEX:
+ if ((*statep & LEVEL_MASK) != ENCODING_LEVEL) {
+ /* TODO warning */
+ break;
+ } else if (*statep & HAVE_FIRST_INDEX_BIT) {
+ /* TODO warning */
+ }
+ r = get_uints(&ju1, &ju2, NULL, 0xFF, line, &line, ctx);
+ if (r < 0) {
+ goto fail;
+ } else if (r == 0) {
+ /* TODO warning */
+ break;
+ } else if (r == 1) {
+ ju2 = 0;
+ *statep &= ~HAVE_FIRST_INDEX_BIT;
+ } else if (r == 2) {
+ *statep |= HAVE_FIRST_INDEX_BYTE_2_BIT;
+ } else {
+ /* TODO warning */
+ break;
+ }
+ if (*line && *line != '\n' && *line != '#') {
+ /* TODO warning */
+ break;
+ }
+ (*encodingp)->first_index_row = (uint16_t)ju1;
+ (*encodingp)->first_index_col = (uint16_t)ju2;
+ *statep |= HAVE_FIRST_INDEX_BIT;
+ break;
+
+ case STARTMAPPING:
+ if ((*statep & LEVEL_MASK) == MAPPING_LEVEL) {
+ /* TODO warning */
+ } else if ((*statep & LEVEL_MASK) != ENCODING_LEVEL) {
+ /* TODO warning */
+ break;
+ }
+ if ((*encodingp)->nmappings > SIZE_MAX / sizeof(*(*encodingp)->mappings) - 1)
+ goto enomem;
+ new = realloc((*encodingp)->mappings, ((*encodingp)->nmappings + 1) * sizeof(*(*encodingp)->mappings));
+ if (!new)
+ goto enomem;
+ (*encodingp)->mappings = new;
+ (*encodingp)->mappings[(*encodingp)->nmappings].entries = NULL;
+ (*encodingp)->mappings[(*encodingp)->nmappings].nentries = 0;
+ (*encodingp)->mappings[(*encodingp)->nmappings].target = get_string(line, &line);
+ if (!(*encodingp)->mappings[(*encodingp)->nmappings].target) {
+ /* TODO warning */
+ break;
+ }
+ if (!*(*encodingp)->mappings[(*encodingp)->nmappings].target) {
+ /* TODO warning */
+ }
+ (*encodingp)->nmappings += 1;
+ *statep = (*statep & ~LEVEL_MASK) | MAPPING_LEVEL;
+ break;
+
+ case ENDMAPPING:
+ if ((*statep & LEVEL_MASK) != MAPPING_LEVEL) {
+ /* TODO warning */
+ break;
+ }
+ if (*line && *line != '\n' && *line != '#') {
+ /* TODO warning */
+ }
+ *statep = (*statep & ~LEVEL_MASK) | ENCODING_LEVEL;
+ break;
+
+ case UNDEFINE:
+ if ((*statep & LEVEL_MASK) != MAPPING_LEVEL) {
+ /* TODO warning */
+ break;
+ }
+ r = get_uints(&ju1, &ju2, NULL, UINT32_C(0xFFFFFFFF), line, &line, ctx);
+ if (r < 0) {
+ goto fail;
+ } else if (r == 0) {
+ /* TODO warning */
+ break;
+ } else if (r == 1) {
+ ju2 = ju1;
+ } else if (r > 2) {
+ /* TODO warning */
+ break;
+ }
+ if (*line && *line != '\n' && *line != '#') {
+ /* TODO warning */
+ break;
+ }
+ mapping = &(*encodingp)->mappings[(*encodingp)->nmappings - 1];
+ if (mapping->nentries > SIZE_MAX / sizeof(*mapping->entries) - 1)
+ goto enomem;
+ new = realloc(mapping->entries, (mapping->nentries + 1) * sizeof(*mapping->entries));
+ if (!new)
+ goto enomem;
+ mapping->entries = new;
+ mapping->entries[mapping->nentries].undefined_range.type = LIBFONTS_ENCODING_MAPPING_ENTRY_UNDEFINED_RANGE;
+ mapping->entries[mapping->nentries].undefined_range.low_source = (uint32_t)ju1;
+ mapping->entries[mapping->nentries].undefined_range.high_source = (uint32_t)ju2;
+ mapping->nentries += 1;
+ break;
+
+ case NO_KEYWORD:
+ if ((*statep & LEVEL_MASK) != MAPPING_LEVEL) {
+ /* TODO warning */
+ break;
+ }
+ r = get_uints(&ju1, &ju2, &ju3, UINT32_C(0xFFFFFFFF), line, &line, ctx);
+ if (r < 0) {
+ goto fail;
+ } else if (r == 0) {
+ /* TODO warning internal error */
+ break;
+ } else if (r == 1) {
+ if (!*line || *line == '\n' || *line == '#') {
+ /* TODO warning */
+ break;
+ }
+ } else if (r == 2) {
+ ju3 = ju2;
+ ju2 = ju1;
+ } else if (r == 3) {
+ if (ju2 < ju1) {
+ /* TODO warning */
+ break;
+ }
+ } else {
+ /* TODO warning */
+ break;
+ }
+ if (r != 1 && *line && *line != '\n' && *line != '#') {
+ /* TODO warning */
+ break;
+ }
+
+ mapping = &(*encodingp)->mappings[(*encodingp)->nmappings - 1];
+ if (mapping->nentries > SIZE_MAX / sizeof(*mapping->entries) - 1)
+ goto enomem;
+ new = realloc(mapping->entries, (mapping->nentries + 1) * sizeof(*mapping->entries));
+ if (!new)
+ goto enomem;
+ mapping->entries = new;
+ if (r != 1) {
+ mapping->entries[mapping->nentries].remapped_range.type = LIBFONTS_ENCODING_MAPPING_ENTRY_REMAPPED_RANGE;
+ mapping->entries[mapping->nentries].remapped_range.low_source = (uint32_t)ju1;
+ mapping->entries[mapping->nentries].remapped_range.high_source = (uint32_t)ju2;
+ mapping->entries[mapping->nentries].remapped_range.low_target = (uint32_t)ju3;
+ } else {
+ mapping->entries[mapping->nentries].index_to_name.type = LIBFONTS_ENCODING_MAPPING_ENTRY_INDEX_TO_NAME;
+ mapping->entries[mapping->nentries].index_to_name.source = (uint32_t)ju1;
+ mapping->entries[mapping->nentries].index_to_name.target = get_string(line, &line);
+ if (!mapping->entries[mapping->nentries].index_to_name.target)
+ goto enomem;
+ }
+ mapping->nentries += 1;
+ break;
+
+ default:
+ /* TODO warning internal error */
+ break;
+ }
+
+out:
+ if (line)
+ while (*line && *line != '\n')
+ line++;
+ if (endp)
+ *endp = *(char **)(void *)&line;
+ return ret;
+
+enomem:
+ errno = ENOMEM;
+fail:
+ ret = -1;
+ goto out;
+
+bad_keyword:
+ /* TODO warning */
+ goto out;
+}
+
+
+#else
+
+
+int
+main(void)
+{
+ return 0; /* XXX add test */
+}
+
+
+#endif