diff options
Diffstat (limited to 'cmap.c')
-rw-r--r-- | cmap.c | 461 |
1 files changed, 461 insertions, 0 deletions
@@ -0,0 +1,461 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static int +get_uint16s(const char *data, size_t size, uint16_t *output, size_t offset, size_t first, size_t count) +{ + uint16_t b1, b2; + if (count > SIZE_MAX - first) { + errno = EFBIG; + return -1; + } + if (offset > size || first + count > (size - offset) / 2) { + errno = EBFONT; + return -1; + } + offset += first * 2; + data = &data[offset]; + for (; count--; output++, data = &data[2]) { + b1 = (uint16_t)((uint16_t)((const uint8_t *)data)[0] << 8); + b2 = (uint16_t)((uint16_t)((const uint8_t *)data)[1] << 0); + *output = (uint16_t)(b1 | b2); + } + return 0; +} + + +int +libparsesfnt_parse_cmap( + const char *data, size_t size, + struct libparsesfnt_cmap *infop, + const struct libparsesfnt_tabdir_entry *tag) +{ + return PARSE(LIBPARSESFNT_CMAP__, tag->offset, 0, 0, 0, 1, tag); +} + + +int +libparsesfnt_parse_cmap_entries( + const char *data, size_t size, + struct libparsesfnt_cmap_entry *infop, + const struct libparsesfnt_tabdir_entry *tag, + size_t first, size_t count) +{ + int ret; + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY__, tag->offset, 4, 0, first, count, tag); + if (!ret) { + for (; count--; infop++) { + if (infop->offset > tag->length - 2) { + errno = EBFONT; + return -1; + } + } + } + return ret; +} + + +int +libparsesfnt_parse_cmap_entry_subtable( + const char *data, size_t size, + union libparsesfnt_cmap_entry_subtable *infop, + const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_cmap_entry *entry) +{ + int ret = 0; + size_t i; + uint16_t u16; + + if (PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE__, tag->offset, entry->offset, 0, 0, 1, tag)) + return -1; + + if (infop->format == 0) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_0__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + if (infop->f0.length != 3 * 2 + 256 || + infop->f0.length > tag->length - entry->offset) + goto ebfont; + } + + } else if (infop->format == 2) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_2__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + u16 = 0; + for (i = 0; i < ELEMSOF(infop->f2.subheader_keys); i++) + if (infop->f2.subheader_keys[i] > u16) + u16 = infop->f2.subheader_keys[i]; + infop->f2.libparsesfnt_subheader_keys_max = u16; + if (u16 > (UINT16_MAX - 8) / 8 - 1 || + infop->f2.length < 8 * 8 * (u16 + 1) || + infop->f2.length > tag->length - entry->offset) + goto ebfont; + } + + } else if (infop->format == 4) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_4__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + if (infop->f4.seg_count_x2 > (UINT16_MAX - 16) / 4 || + infop->f4.length < 16 + 4 * infop->f4.seg_count_x2 || + infop->f4.length > tag->length - entry->offset) + goto ebfont; + } + + } else if (infop->format == 6) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_6__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + if (infop->f6.entry_count > UINT16_MAX / 2 - 5 || + infop->f6.length != (5 + infop->f6.entry_count) * 2 || + infop->f6.length > tag->length - entry->offset) + goto ebfont; + } + + } else if (infop->format == 8) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_8__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + if (infop->f8.n_groups > (UINT32_MAX - 16 - 8192) / 12 || + infop->f8.length != 16 + 8192 + infop->f8.n_groups * 12 || + infop->f8.length > tag->length - entry->offset) + goto ebfont; + } + + } else if (infop->format == 10) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_10__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + if (infop->f10.num_chars > (UINT32_MAX - 20) / 2 || + infop->f10.length != 20 + infop->f10.num_chars * 2 || + infop->f10.length > tag->length - entry->offset) + goto ebfont; + } + + } else if (infop->format == 12) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_12__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + if (infop->f12.n_groups > (UINT32_MAX - 16) / 12 || + infop->f12.length != 16 + infop->f12.n_groups * 12 || + infop->f12.length > tag->length - entry->offset) + goto ebfont; + } + + } else if (infop->format == 13) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_13__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + if (infop->f13.n_groups > (UINT32_MAX - 16) / 12 || + infop->f13.length != 16 + infop->f13.n_groups * 12 || + infop->f13.length > tag->length - entry->offset) + goto ebfont; + } + + } else if (infop->format == 14) { + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_14__, tag->offset, entry->offset, 0, 0, 1, tag); + if (!ret) { + if (infop->f14.num_var_selector_records > (UINT32_MAX - 12) / 12 || + infop->f14.length < 12 + infop->f14.num_var_selector_records * 12 || + infop->f14.length > tag->length - entry->offset) + goto ebfont; + } + + } else { + goto ebfont; + } + return ret; + +ebfont: + errno = EBFONT; + return -1; +} + + +int +libparsesfnt_parse_cmap_entry_subtable_2_subheader_entries( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_2_subheader *infop, + const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_cmap_entry *entry, + size_t first, size_t count) +{ + return PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_2_SUBHEADER__, tag->offset, entry->offset, 259 * 2, first, count, tag); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_2_glyph_index_entries( + const char *data, size_t size, + uint16_t *glyph_indexp, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_2 *subtable, + size_t first, size_t count) +{ + size_t offset; + offset = 259 * 2 + ((size_t)subtable->libparsesfnt_subheader_keys_max + 1) * 8; + if (first + count > (subtable->length - offset) / 2) { + errno = EBFONT; + return -1; + } + offset += tag->offset + entry->offset; + return get_uint16s(data, size, glyph_indexp, offset, first, count); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_4_end_code_entries( + const char *data, size_t size, + uint16_t *end_codep, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + size_t first, size_t count) +{ + return get_uint16s(data, size, end_codep, tag->offset + entry->offset + 14, first, count); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_4_start_code_entries( + const char *data, size_t size, + uint16_t *start_codep, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_4 *subtable, + size_t first, size_t count) +{ + return get_uint16s(data, size, start_codep, tag->offset + entry->offset + 16 + 1 * subtable->seg_count_x2, first, count); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_4_id_delta_entries( + const char *data, size_t size, + uint16_t *id_deltap, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_4 *subtable, + size_t first, size_t count) +{ + return get_uint16s(data, size, id_deltap, tag->offset + entry->offset + 16 + 2 * subtable->seg_count_x2, first, count); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_4_id_range_offset_entries( + const char *data, size_t size, + uint16_t *id_range_offsetp, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_4 *subtable, + size_t first, size_t count) +{ + return get_uint16s(data, size, id_range_offsetp, tag->offset + entry->offset + 16 + 3 * subtable->seg_count_x2, first, count); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_4_glyph_index_entries( + const char *data, size_t size, + uint16_t *glyph_indexp, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_4 *subtable, + size_t first, size_t count) +{ + if (count > SIZE_MAX - first) { + errno = EFBIG; + return -1; + } + if (first + count > (tag->length - entry->offset - 16 - 4 * subtable->seg_count_x2) / 2) { + errno = EBFONT; + return -1; + } + return get_uint16s(data, size, glyph_indexp, tag->offset + entry->offset + 16 + 4 * subtable->seg_count_x2, first, count); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_6_entries( + const char *data, size_t size, + uint16_t *glyphp, + const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_cmap_entry *entry, + size_t first, size_t count) +{ + return get_uint16s(data, size, glyphp, tag->offset + entry->offset + 10, first, count); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_8_entries( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_8_entry *infop, + const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_cmap_entry *entry, + size_t first, size_t count) +{ + return PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_8_ENTRY__, tag->offset, entry->offset, 16 + 8192, first, count, tag); +} + +int +libparsesfnt_parse_cmap_entry_subtable_10_entries( + const char *data, size_t size, + uint16_t *glyphp, + const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_cmap_entry *entry, + size_t first, size_t count) +{ + return get_uint16s(data, size, glyphp, tag->offset + entry->offset + 10, first, count); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_12_entries( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_12_entry *infop, + const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_cmap_entry *entry, + size_t first, size_t count) +{ + return PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_12_ENTRY__, tag->offset, entry->offset, 16, first, count, tag); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_13_entries( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_13_entry *infop, + const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_cmap_entry *entry, + size_t first, size_t count) +{ + return PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_13_ENTRY__, tag->offset, entry->offset, 16, first, count, tag); +} + + +int +libparsesfnt_parse_cmap_entry_subtable_14_entries( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_14_entry *infop, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_14 *subtable, + size_t first, size_t count) +{ + int ret; + uint8_t high; + union { uint16_t u16; uint8_t u8s[2]; } low; + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_14_ENTRY__, tag->offset, entry->offset, 10, first, count, tag); + if (!ret) { + for (; count--; infop++) { + high = ((uint8_t *)infop)[1]; + low.u8s[0] = ((uint8_t *)infop)[2]; + low.u8s[1] = ((uint8_t *)infop)[3]; + infop->var_selector = ((uint32_t)high << 16) | (uint32_t)low.u16; + if (infop->default_uvs_offset) { + if (infop->default_uvs_offset > subtable->length || + 4 > subtable->length - infop->default_uvs_offset) { + goto ebfont; + } + } + if (infop->non_default_uvs_offset) { + if (infop->non_default_uvs_offset > subtable->length || + 4 > subtable->length - infop->non_default_uvs_offset) { + goto ebfont; + } + } + } + } + return 0; + +ebfont: + errno = EBFONT; + return -1; +} + + +int +libparsesfnt_parse_cmap_entry_subtable_14_default_uvs( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_14_default_uvs *infop, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_14 *subtable, + const struct libparsesfnt_cmap_entry_subtable_14_entry *subentry) +{ + int ret; + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_14_DEFAULT_UVS__, + tag->offset, entry->offset, subentry->default_uvs_offset, 0, 1, tag); + if (!ret) { + if (infop->num_unicode_value_ranges > subtable->length / 4) { + errno = EBFONT; + return -1; + } + } + return ret; +} + + +int +libparsesfnt_parse_cmap_entry_subtable_14_default_uvs_entries( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_14_default_uvs_entry *infop, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_14_entry *subentry, + size_t first, size_t count) +{ + int ret; + uint8_t high; + union { uint16_t u16; uint8_t u8s[2]; } low; + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_14_DEFAULT_UVS_ENTRY__, + (size_t)tag->offset + (size_t)entry->offset, subentry->default_uvs_offset, 4, + first, count, tag); + if (!ret) { + for (; count--; infop++) { + high = ((uint8_t *)infop)[1]; + low.u8s[0] = ((uint8_t *)infop)[2]; + low.u8s[1] = ((uint8_t *)infop)[3]; + infop->start_unicode_value = ((uint32_t)high << 16) | (uint32_t)low.u16; + } + } + return ret; +} + + +int +libparsesfnt_parse_cmap_entry_subtable_14_non_default_uvs( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_14_non_default_uvs *infop, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_14 *subtable, + const struct libparsesfnt_cmap_entry_subtable_14_entry *subentry) +{ + int ret; + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_14_NON_DEFAULT_UVS__, + tag->offset, entry->offset, subentry->non_default_uvs_offset, 0, 1, tag); + if (!ret) { + if (infop->num_uvs_mappings > subtable->length / 4) { + errno = EBFONT; + return -1; + } + } + return ret; +} + + +int +libparsesfnt_parse_cmap_entry_subtable_14_non_default_uvs_entries( + const char *data, size_t size, + struct libparsesfnt_cmap_entry_subtable_14_non_default_uvs_entry *infop, + const struct libparsesfnt_tabdir_entry *tag, + const struct libparsesfnt_cmap_entry *entry, + const struct libparsesfnt_cmap_entry_subtable_14_entry *subentry, + size_t first, size_t count) +{ + int ret; + uint8_t high; + union { uint16_t u16; uint8_t u8s[2]; } low; + ret = PARSE(LIBPARSESFNT_CMAP_ENTRY_SUBTABLE_14_NON_DEFAULT_UVS_ENTRY__, + (size_t)tag->offset + (size_t)entry->offset, subentry->non_default_uvs_offset, 4, + first, count, tag); + if (!ret) { + for (; count--; infop++) { + high = ((uint8_t *)infop)[1]; + low.u8s[0] = ((uint8_t *)infop)[2]; + low.u8s[1] = ((uint8_t *)infop)[3]; + infop->start_unicode_value = ((uint32_t)high << 16) | (uint32_t)low.u16; + } + } + return ret; +} |