summaryrefslogtreecommitdiffstats
path: root/cmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmap.c')
-rw-r--r--cmap.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/cmap.c b/cmap.c
new file mode 100644
index 0000000..ac37a3b
--- /dev/null
+++ b/cmap.c
@@ -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;
+}