From 9c039f8d00fa787ef5be81df139a78bb68820b8e Mon Sep 17 00:00:00 2001 From: harrand Date: Sat, 23 Sep 2023 02:38:57 +0100 Subject: [PATCH] [ttf] properly parse head table when parsing ttf. still lots more tables to go... --- src/tz/io/ttf.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++- src/tz/io/ttf.hpp | 28 +++++++++++++++- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/src/tz/io/ttf.cpp b/src/tz/io/ttf.cpp index 3661d960f4..e3ad826951 100644 --- a/src/tz/io/ttf.cpp +++ b/src/tz/io/ttf.cpp @@ -8,6 +8,12 @@ namespace tz::io { + template + T ttf_read_value(const char* data) + { + return tz::big_endian(*reinterpret_cast(data)); + } + ttf ttf::from_memory(std::string_view sv) { TZ_PROFZONE("ttf - from memory", 0xFFFF2222); @@ -28,6 +34,9 @@ namespace tz::io std::string_view ttf_minus_header = this->parse_header(ttf_data); this->parse_header(ttf_data); this->parse_table_info(ttf_minus_header, ttf_data); + // by the time we've parsed tables, we expect all the tables to be sorted. + // let's do a sanity check ensuring that the canary of the head table has been set to true. + tz::assert(this->head.canary, "TTF Head Table canary value was never set to true, this means that a head table was not located. Most likely the TTF is malformed or corrupted."); } std::string_view ttf::parse_header(std::string_view str) @@ -66,10 +75,16 @@ namespace tz::io tbl.length = tz::big_endian(*reinterpret_cast(ptr)); ptr += sizeof(std::uint32_t); - if(tbl.tag[0] != 'h' || tbl.tag[1] != 'e' || tbl.tag[2] != 'a' || tbl.tag[3] != 'd') + if(std::string{tbl.tag} == "head") + { + this->parse_head_table(full_data, tbl); + } + else { std::uint32_t calc = calculate_table_checksum(full_data, tbl.offset, tbl.length); tz::assert(calc == tbl.checksum); + + // parse other table types... } } } @@ -83,4 +98,72 @@ namespace tz::io } return sum; } + + void ttf::parse_head_table(std::string_view data, ttf_table table_descriptor) + { + tz::assert(data.size() > table_descriptor.offset + table_descriptor.length); + data.remove_prefix(table_descriptor.offset); + data.remove_suffix(data.size() - table_descriptor.length); + tz::assert(data.size() == (table_descriptor.length)); + + tz::assert(!this->head.canary, "When parsing head table, noticed canary already switched to true. Double head table discovery? Most likely malformed TTF."); + + const char* ptr = data.data(); + + this->head.major_version = ttf_read_value(ptr); + ptr += sizeof(this->head.major_version); + + this->head.minor_version = ttf_read_value(ptr); + ptr += sizeof(this->head.minor_version); + + this->head.font_revision_fixed_point = ttf_read_value(ptr); + // fixed-point conversion: divide by (1 >> 16) + this->head.font_revision_fixed_point /= (1 << 16); + ptr += sizeof(this->head.font_revision_fixed_point); + + this->head.checksum_adjustment = ttf_read_value(ptr); + ptr += sizeof(this->head.checksum_adjustment); + + this->head.magic = ttf_read_value(ptr); + ptr += sizeof(this->head.magic); + + this->head.flags = ttf_read_value(ptr); + ptr += sizeof(this->head.flags); + + this->head.units_per_em = ttf_read_value(ptr); + ptr += sizeof(this->head.units_per_em); + + // ignore created and modified date for now. aids. + ptr += sizeof(std::uint64_t) * 2; + + this->head.xmin = ttf_read_value(ptr); + ptr += sizeof(this->head.xmin); + + this->head.ymin = ttf_read_value(ptr); + ptr += sizeof(this->head.ymin); + + this->head.xmax = ttf_read_value(ptr); + ptr += sizeof(this->head.xmax); + + this->head.ymax = ttf_read_value(ptr); + ptr += sizeof(this->head.ymax); + + this->head.mac_style = ttf_read_value(ptr); + ptr += sizeof(this->head.mac_style); + + this->head.lowest_rec_ppem = ttf_read_value(ptr); + ptr += sizeof(this->head.lowest_rec_ppem); + + this->head.font_direction_hint = ttf_read_value(ptr); + ptr += sizeof(this->head.font_direction_hint); + + this->head.index_to_loc_format = ttf_read_value(ptr); + ptr += sizeof(this->head.index_to_loc_format); + + this->head.glyph_data_format = ttf_read_value(ptr); + ptr += sizeof(this->head.glyph_data_format); + + // set canary to true, meaning we did indeed set the head table. + this->head.canary = true; + } } \ No newline at end of file diff --git a/src/tz/io/ttf.hpp b/src/tz/io/ttf.hpp index 69f234fef2..30c045f36d 100644 --- a/src/tz/io/ttf.hpp +++ b/src/tz/io/ttf.hpp @@ -16,12 +16,35 @@ namespace tz::io struct ttf_table { - char tag[4]; + char tag[5] = "DEAD"; std::uint32_t checksum = 0u; std::uint32_t offset = 0u; std::uint32_t length = 0u; }; + struct ttf_head_table + { + std::uint16_t major_version = 0u; + std::uint16_t minor_version = 0u; + std::int32_t font_revision_fixed_point = 0; + std::uint32_t checksum_adjustment = 0u; + std::uint32_t magic = 0u; + std::uint16_t flags = 0u; + std::uint16_t units_per_em = 0u; + std::uint64_t created_date = 0u; + std::uint64_t modified_date = 0u; + std::int16_t xmin = 0; + std::int16_t ymin = 0; + std::int16_t xmax = std::numeric_limits::max(); + std::int16_t ymax = std::numeric_limits::max(); + std::uint16_t mac_style = 0u; + std::uint16_t lowest_rec_ppem = 0u; + std::int16_t font_direction_hint = 0; + std::int16_t index_to_loc_format = 0; + std::int16_t glyph_data_format = 0; + bool canary = false; + }; + class ttf { public: @@ -33,8 +56,11 @@ namespace tz::io std::string_view parse_header(std::string_view str); void parse_table_info(std::string_view str, std::string_view full_data); std::uint32_t calculate_table_checksum(std::string_view data, std::uint32_t offset, std::uint32_t length) const; + void parse_head_table(std::string_view data, ttf_table table_descriptor); ttf_header header = {}; + std::vector tables = {}; + ttf_head_table head = {}; }; }