/* 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; }