diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index d863a2c3a..7afe61710 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh @@ -136,7 +136,14 @@ struct hb_serialize_context_t template bool check_equal (T1 &&v1, T2 &&v2) - { return check_success ((long long) v1 == (long long) v2); } + { + if ((long long) v1 != (long long) v2) + { + err_offset_overflow (); + return false; + } + return true; + } template bool check_assign (T1 &v1, T2 &&v2) @@ -400,6 +407,7 @@ struct hb_serialize_context_t /* Following two functions exist to allow setting breakpoint on. */ void err_ran_out_of_room () { this->ran_out_of_room = true; } + void err_offset_overflow () { this->offset_overflow = true; } void err_other_error () { this->successful = false; } template @@ -520,7 +528,7 @@ struct hb_serialize_context_t (char *) b.arrayZ, free); } - const hb_vector_t& object_graph() + const hb_vector_t& object_graph() const { return packed; } private: @@ -537,6 +545,7 @@ struct hb_serialize_context_t unsigned int debug_depth; bool successful; bool ran_out_of_room; + bool offset_overflow; private: diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 8b77ecd45..c68f64bc6 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -50,6 +50,7 @@ #include "hb-ot-layout-gpos-table.hh" #include "hb-ot-var-gvar-table.hh" #include "hb-ot-var-hvar-table.hh" +#include "hb-repacker.hh" static unsigned @@ -64,6 +65,32 @@ _plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len) return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); } +/* + * Repack the serialization buffer if any offset overflows exist. + */ +static hb_blob_t* +_repack (const hb_serialize_context_t& c) +{ + if (!c.offset_overflow) + return c.copy_blob (); + + hb_vector_t buf; + int buf_size = c.end - c.start; + if (unlikely (!buf.alloc (buf_size))) + return nullptr; + + hb_serialize_context_t repacked ((void *) buf, buf_size); + hb_resolve_overflows (c.object_graph (), &repacked); + + if (unlikely (repacked.ran_out_of_room || repacked.in_error () || repacked.offset_overflow)) + // TODO(garretrieger): refactor so we can share the resize/retry logic with the subset + // portion. + return nullptr; + + return repacked.copy_blob (); +} + + template static bool _subset (hb_subset_plan_t *plan) @@ -111,7 +138,8 @@ _subset (hb_subset_plan_t *plan) { if (needed) { - hb_blob_t *dest_blob = serializer.copy_blob (); + hb_blob_t *dest_blob = _repack (serializer); + if (!dest_blob) return false; DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length); result = c.plan->add_table (tag, dest_blob); hb_blob_destroy (dest_blob);