1*2d1272b8SAndroid Build Coastguard Worker /* 2*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 3*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2012,2018 Google, Inc. 4*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2019 Facebook, Inc. 5*2d1272b8SAndroid Build Coastguard Worker * 6*2d1272b8SAndroid Build Coastguard Worker * This is part of HarfBuzz, a text shaping library. 7*2d1272b8SAndroid Build Coastguard Worker * 8*2d1272b8SAndroid Build Coastguard Worker * Permission is hereby granted, without written agreement and without 9*2d1272b8SAndroid Build Coastguard Worker * license or royalty fees, to use, copy, modify, and distribute this 10*2d1272b8SAndroid Build Coastguard Worker * software and its documentation for any purpose, provided that the 11*2d1272b8SAndroid Build Coastguard Worker * above copyright notice and the following two paragraphs appear in 12*2d1272b8SAndroid Build Coastguard Worker * all copies of this software. 13*2d1272b8SAndroid Build Coastguard Worker * 14*2d1272b8SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15*2d1272b8SAndroid Build Coastguard Worker * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16*2d1272b8SAndroid Build Coastguard Worker * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17*2d1272b8SAndroid Build Coastguard Worker * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18*2d1272b8SAndroid Build Coastguard Worker * DAMAGE. 19*2d1272b8SAndroid Build Coastguard Worker * 20*2d1272b8SAndroid Build Coastguard Worker * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21*2d1272b8SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22*2d1272b8SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23*2d1272b8SAndroid Build Coastguard Worker * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24*2d1272b8SAndroid Build Coastguard Worker * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25*2d1272b8SAndroid Build Coastguard Worker * 26*2d1272b8SAndroid Build Coastguard Worker * Red Hat Author(s): Behdad Esfahbod 27*2d1272b8SAndroid Build Coastguard Worker * Google Author(s): Behdad Esfahbod 28*2d1272b8SAndroid Build Coastguard Worker * Facebook Author(s): Behdad Esfahbod 29*2d1272b8SAndroid Build Coastguard Worker */ 30*2d1272b8SAndroid Build Coastguard Worker 31*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_SERIALIZE_HH 32*2d1272b8SAndroid Build Coastguard Worker #define HB_SERIALIZE_HH 33*2d1272b8SAndroid Build Coastguard Worker 34*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh" 35*2d1272b8SAndroid Build Coastguard Worker #include "hb-blob.hh" 36*2d1272b8SAndroid Build Coastguard Worker #include "hb-map.hh" 37*2d1272b8SAndroid Build Coastguard Worker #include "hb-pool.hh" 38*2d1272b8SAndroid Build Coastguard Worker 39*2d1272b8SAndroid Build Coastguard Worker #ifdef HB_EXPERIMENTAL_API 40*2d1272b8SAndroid Build Coastguard Worker #include "hb-subset-repacker.h" 41*2d1272b8SAndroid Build Coastguard Worker #endif 42*2d1272b8SAndroid Build Coastguard Worker 43*2d1272b8SAndroid Build Coastguard Worker /* 44*2d1272b8SAndroid Build Coastguard Worker * Serialize 45*2d1272b8SAndroid Build Coastguard Worker */ 46*2d1272b8SAndroid Build Coastguard Worker 47*2d1272b8SAndroid Build Coastguard Worker enum hb_serialize_error_t { 48*2d1272b8SAndroid Build Coastguard Worker HB_SERIALIZE_ERROR_NONE = 0x00000000u, 49*2d1272b8SAndroid Build Coastguard Worker HB_SERIALIZE_ERROR_OTHER = 0x00000001u, 50*2d1272b8SAndroid Build Coastguard Worker HB_SERIALIZE_ERROR_OFFSET_OVERFLOW = 0x00000002u, 51*2d1272b8SAndroid Build Coastguard Worker HB_SERIALIZE_ERROR_OUT_OF_ROOM = 0x00000004u, 52*2d1272b8SAndroid Build Coastguard Worker HB_SERIALIZE_ERROR_INT_OVERFLOW = 0x00000008u, 53*2d1272b8SAndroid Build Coastguard Worker HB_SERIALIZE_ERROR_ARRAY_OVERFLOW = 0x00000010u 54*2d1272b8SAndroid Build Coastguard Worker }; 55*2d1272b8SAndroid Build Coastguard Worker HB_MARK_AS_FLAG_T (hb_serialize_error_t); 56*2d1272b8SAndroid Build Coastguard Worker 57*2d1272b8SAndroid Build Coastguard Worker struct hb_serialize_context_t 58*2d1272b8SAndroid Build Coastguard Worker { 59*2d1272b8SAndroid Build Coastguard Worker typedef unsigned objidx_t; 60*2d1272b8SAndroid Build Coastguard Worker 61*2d1272b8SAndroid Build Coastguard Worker enum whence_t { 62*2d1272b8SAndroid Build Coastguard Worker Head, /* Relative to the current object head (default). */ 63*2d1272b8SAndroid Build Coastguard Worker Tail, /* Relative to the current object tail after packed. */ 64*2d1272b8SAndroid Build Coastguard Worker Absolute /* Absolute: from the start of the serialize buffer. */ 65*2d1272b8SAndroid Build Coastguard Worker }; 66*2d1272b8SAndroid Build Coastguard Worker 67*2d1272b8SAndroid Build Coastguard Worker 68*2d1272b8SAndroid Build Coastguard Worker 69*2d1272b8SAndroid Build Coastguard Worker struct object_t 70*2d1272b8SAndroid Build Coastguard Worker { finihb_serialize_context_t::object_t71*2d1272b8SAndroid Build Coastguard Worker void fini () { 72*2d1272b8SAndroid Build Coastguard Worker real_links.fini (); 73*2d1272b8SAndroid Build Coastguard Worker virtual_links.fini (); 74*2d1272b8SAndroid Build Coastguard Worker } 75*2d1272b8SAndroid Build Coastguard Worker 76*2d1272b8SAndroid Build Coastguard Worker object_t () = default; 77*2d1272b8SAndroid Build Coastguard Worker 78*2d1272b8SAndroid Build Coastguard Worker #ifdef HB_EXPERIMENTAL_API object_thb_serialize_context_t::object_t79*2d1272b8SAndroid Build Coastguard Worker object_t (const hb_object_t &o) 80*2d1272b8SAndroid Build Coastguard Worker { 81*2d1272b8SAndroid Build Coastguard Worker head = o.head; 82*2d1272b8SAndroid Build Coastguard Worker tail = o.tail; 83*2d1272b8SAndroid Build Coastguard Worker next = nullptr; 84*2d1272b8SAndroid Build Coastguard Worker real_links.alloc (o.num_real_links, true); 85*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0 ; i < o.num_real_links; i++) 86*2d1272b8SAndroid Build Coastguard Worker real_links.push (o.real_links[i]); 87*2d1272b8SAndroid Build Coastguard Worker 88*2d1272b8SAndroid Build Coastguard Worker virtual_links.alloc (o.num_virtual_links, true); 89*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < o.num_virtual_links; i++) 90*2d1272b8SAndroid Build Coastguard Worker virtual_links.push (o.virtual_links[i]); 91*2d1272b8SAndroid Build Coastguard Worker } 92*2d1272b8SAndroid Build Coastguard Worker #endif 93*2d1272b8SAndroid Build Coastguard Worker add_virtual_linkhb_serialize_context_t::object_t94*2d1272b8SAndroid Build Coastguard Worker bool add_virtual_link (objidx_t objidx) 95*2d1272b8SAndroid Build Coastguard Worker { 96*2d1272b8SAndroid Build Coastguard Worker if (!objidx) 97*2d1272b8SAndroid Build Coastguard Worker return false; 98*2d1272b8SAndroid Build Coastguard Worker 99*2d1272b8SAndroid Build Coastguard Worker auto& link = *virtual_links.push (); 100*2d1272b8SAndroid Build Coastguard Worker if (virtual_links.in_error ()) 101*2d1272b8SAndroid Build Coastguard Worker return false; 102*2d1272b8SAndroid Build Coastguard Worker 103*2d1272b8SAndroid Build Coastguard Worker link.objidx = objidx; 104*2d1272b8SAndroid Build Coastguard Worker // Remaining fields were previously zero'd by push(): 105*2d1272b8SAndroid Build Coastguard Worker // link.width = 0; 106*2d1272b8SAndroid Build Coastguard Worker // link.is_signed = 0; 107*2d1272b8SAndroid Build Coastguard Worker // link.whence = 0; 108*2d1272b8SAndroid Build Coastguard Worker // link.position = 0; 109*2d1272b8SAndroid Build Coastguard Worker // link.bias = 0; 110*2d1272b8SAndroid Build Coastguard Worker 111*2d1272b8SAndroid Build Coastguard Worker return true; 112*2d1272b8SAndroid Build Coastguard Worker } 113*2d1272b8SAndroid Build Coastguard Worker swaphb_serialize_context_t114*2d1272b8SAndroid Build Coastguard Worker friend void swap (object_t& a, object_t& b) noexcept 115*2d1272b8SAndroid Build Coastguard Worker { 116*2d1272b8SAndroid Build Coastguard Worker hb_swap (a.head, b.head); 117*2d1272b8SAndroid Build Coastguard Worker hb_swap (a.tail, b.tail); 118*2d1272b8SAndroid Build Coastguard Worker hb_swap (a.next, b.next); 119*2d1272b8SAndroid Build Coastguard Worker hb_swap (a.real_links, b.real_links); 120*2d1272b8SAndroid Build Coastguard Worker hb_swap (a.virtual_links, b.virtual_links); 121*2d1272b8SAndroid Build Coastguard Worker } 122*2d1272b8SAndroid Build Coastguard Worker operator ==hb_serialize_context_t::object_t123*2d1272b8SAndroid Build Coastguard Worker bool operator == (const object_t &o) const 124*2d1272b8SAndroid Build Coastguard Worker { 125*2d1272b8SAndroid Build Coastguard Worker // Virtual links aren't considered for equality since they don't affect the functionality 126*2d1272b8SAndroid Build Coastguard Worker // of the object. 127*2d1272b8SAndroid Build Coastguard Worker return (tail - head == o.tail - o.head) 128*2d1272b8SAndroid Build Coastguard Worker && (real_links.length == o.real_links.length) 129*2d1272b8SAndroid Build Coastguard Worker && 0 == hb_memcmp (head, o.head, tail - head) 130*2d1272b8SAndroid Build Coastguard Worker && real_links.as_bytes () == o.real_links.as_bytes (); 131*2d1272b8SAndroid Build Coastguard Worker } hashhb_serialize_context_t::object_t132*2d1272b8SAndroid Build Coastguard Worker uint32_t hash () const 133*2d1272b8SAndroid Build Coastguard Worker { 134*2d1272b8SAndroid Build Coastguard Worker // Virtual links aren't considered for equality since they don't affect the functionality 135*2d1272b8SAndroid Build Coastguard Worker // of the object. 136*2d1272b8SAndroid Build Coastguard Worker return hb_bytes_t (head, hb_min (128, tail - head)).hash () ^ 137*2d1272b8SAndroid Build Coastguard Worker real_links.as_bytes ().hash (); 138*2d1272b8SAndroid Build Coastguard Worker } 139*2d1272b8SAndroid Build Coastguard Worker 140*2d1272b8SAndroid Build Coastguard Worker struct link_t 141*2d1272b8SAndroid Build Coastguard Worker { 142*2d1272b8SAndroid Build Coastguard Worker unsigned width: 3; 143*2d1272b8SAndroid Build Coastguard Worker unsigned is_signed: 1; 144*2d1272b8SAndroid Build Coastguard Worker unsigned whence: 2; 145*2d1272b8SAndroid Build Coastguard Worker unsigned bias : 26; 146*2d1272b8SAndroid Build Coastguard Worker unsigned position; 147*2d1272b8SAndroid Build Coastguard Worker objidx_t objidx; 148*2d1272b8SAndroid Build Coastguard Worker 149*2d1272b8SAndroid Build Coastguard Worker link_t () = default; 150*2d1272b8SAndroid Build Coastguard Worker 151*2d1272b8SAndroid Build Coastguard Worker #ifdef HB_EXPERIMENTAL_API link_thb_serialize_context_t::object_t::link_t152*2d1272b8SAndroid Build Coastguard Worker link_t (const hb_link_t &o) 153*2d1272b8SAndroid Build Coastguard Worker { 154*2d1272b8SAndroid Build Coastguard Worker width = o.width; 155*2d1272b8SAndroid Build Coastguard Worker is_signed = 0; 156*2d1272b8SAndroid Build Coastguard Worker whence = 0; 157*2d1272b8SAndroid Build Coastguard Worker position = o.position; 158*2d1272b8SAndroid Build Coastguard Worker bias = 0; 159*2d1272b8SAndroid Build Coastguard Worker objidx = o.objidx; 160*2d1272b8SAndroid Build Coastguard Worker } 161*2d1272b8SAndroid Build Coastguard Worker #endif 162*2d1272b8SAndroid Build Coastguard Worker cmphb_serialize_context_t::object_t::link_t163*2d1272b8SAndroid Build Coastguard Worker HB_INTERNAL static int cmp (const void* a, const void* b) 164*2d1272b8SAndroid Build Coastguard Worker { 165*2d1272b8SAndroid Build Coastguard Worker int cmp = ((const link_t*)a)->position - ((const link_t*)b)->position; 166*2d1272b8SAndroid Build Coastguard Worker if (cmp) return cmp; 167*2d1272b8SAndroid Build Coastguard Worker 168*2d1272b8SAndroid Build Coastguard Worker return ((const link_t*)a)->objidx - ((const link_t*)b)->objidx; 169*2d1272b8SAndroid Build Coastguard Worker } 170*2d1272b8SAndroid Build Coastguard Worker }; 171*2d1272b8SAndroid Build Coastguard Worker 172*2d1272b8SAndroid Build Coastguard Worker char *head; 173*2d1272b8SAndroid Build Coastguard Worker char *tail; 174*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<link_t> real_links; 175*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<link_t> virtual_links; 176*2d1272b8SAndroid Build Coastguard Worker object_t *next; 177*2d1272b8SAndroid Build Coastguard Worker 178*2d1272b8SAndroid Build Coastguard Worker auto all_links () const HB_AUTO_RETURN 179*2d1272b8SAndroid Build Coastguard Worker (( hb_concat (real_links, virtual_links) )); 180*2d1272b8SAndroid Build Coastguard Worker auto all_links_writer () HB_AUTO_RETURN 181*2d1272b8SAndroid Build Coastguard Worker (( hb_concat (real_links.writer (), virtual_links.writer ()) )); 182*2d1272b8SAndroid Build Coastguard Worker }; 183*2d1272b8SAndroid Build Coastguard Worker 184*2d1272b8SAndroid Build Coastguard Worker struct snapshot_t 185*2d1272b8SAndroid Build Coastguard Worker { 186*2d1272b8SAndroid Build Coastguard Worker char *head; 187*2d1272b8SAndroid Build Coastguard Worker char *tail; 188*2d1272b8SAndroid Build Coastguard Worker object_t *current; // Just for sanity check 189*2d1272b8SAndroid Build Coastguard Worker unsigned num_real_links; 190*2d1272b8SAndroid Build Coastguard Worker unsigned num_virtual_links; 191*2d1272b8SAndroid Build Coastguard Worker hb_serialize_error_t errors; 192*2d1272b8SAndroid Build Coastguard Worker }; 193*2d1272b8SAndroid Build Coastguard Worker snapshothb_serialize_context_t194*2d1272b8SAndroid Build Coastguard Worker snapshot_t snapshot () 195*2d1272b8SAndroid Build Coastguard Worker { 196*2d1272b8SAndroid Build Coastguard Worker return snapshot_t { 197*2d1272b8SAndroid Build Coastguard Worker head, tail, current, 198*2d1272b8SAndroid Build Coastguard Worker current ? current->real_links.length : 0, 199*2d1272b8SAndroid Build Coastguard Worker current ? current->virtual_links.length : 0, 200*2d1272b8SAndroid Build Coastguard Worker errors 201*2d1272b8SAndroid Build Coastguard Worker }; 202*2d1272b8SAndroid Build Coastguard Worker } 203*2d1272b8SAndroid Build Coastguard Worker hb_serialize_context_thb_serialize_context_t204*2d1272b8SAndroid Build Coastguard Worker hb_serialize_context_t (void *start_, unsigned int size) : 205*2d1272b8SAndroid Build Coastguard Worker start ((char *) start_), 206*2d1272b8SAndroid Build Coastguard Worker end (start + size), 207*2d1272b8SAndroid Build Coastguard Worker current (nullptr) 208*2d1272b8SAndroid Build Coastguard Worker { reset (); } ~hb_serialize_context_thb_serialize_context_t209*2d1272b8SAndroid Build Coastguard Worker ~hb_serialize_context_t () { fini (); } 210*2d1272b8SAndroid Build Coastguard Worker finihb_serialize_context_t211*2d1272b8SAndroid Build Coastguard Worker void fini () 212*2d1272b8SAndroid Build Coastguard Worker { 213*2d1272b8SAndroid Build Coastguard Worker for (object_t *_ : ++hb_iter (packed)) _->fini (); 214*2d1272b8SAndroid Build Coastguard Worker packed.fini (); 215*2d1272b8SAndroid Build Coastguard Worker this->packed_map.fini (); 216*2d1272b8SAndroid Build Coastguard Worker 217*2d1272b8SAndroid Build Coastguard Worker while (current) 218*2d1272b8SAndroid Build Coastguard Worker { 219*2d1272b8SAndroid Build Coastguard Worker auto *_ = current; 220*2d1272b8SAndroid Build Coastguard Worker current = current->next; 221*2d1272b8SAndroid Build Coastguard Worker _->fini (); 222*2d1272b8SAndroid Build Coastguard Worker } 223*2d1272b8SAndroid Build Coastguard Worker } 224*2d1272b8SAndroid Build Coastguard Worker in_errorhb_serialize_context_t225*2d1272b8SAndroid Build Coastguard Worker bool in_error () const { return bool (errors); } 226*2d1272b8SAndroid Build Coastguard Worker successfulhb_serialize_context_t227*2d1272b8SAndroid Build Coastguard Worker bool successful () const { return !bool (errors); } 228*2d1272b8SAndroid Build Coastguard Worker ran_out_of_roomhb_serialize_context_t229*2d1272b8SAndroid Build Coastguard Worker HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; } offset_overflowhb_serialize_context_t230*2d1272b8SAndroid Build Coastguard Worker HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; } only_offset_overflowhb_serialize_context_t231*2d1272b8SAndroid Build Coastguard Worker HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; } only_overflowhb_serialize_context_t232*2d1272b8SAndroid Build Coastguard Worker HB_NODISCARD bool only_overflow () const 233*2d1272b8SAndroid Build Coastguard Worker { 234*2d1272b8SAndroid Build Coastguard Worker return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW 235*2d1272b8SAndroid Build Coastguard Worker || errors == HB_SERIALIZE_ERROR_INT_OVERFLOW 236*2d1272b8SAndroid Build Coastguard Worker || errors == HB_SERIALIZE_ERROR_ARRAY_OVERFLOW; 237*2d1272b8SAndroid Build Coastguard Worker } 238*2d1272b8SAndroid Build Coastguard Worker resethb_serialize_context_t239*2d1272b8SAndroid Build Coastguard Worker void reset (void *start_, unsigned int size) 240*2d1272b8SAndroid Build Coastguard Worker { 241*2d1272b8SAndroid Build Coastguard Worker start = (char*) start_; 242*2d1272b8SAndroid Build Coastguard Worker end = start + size; 243*2d1272b8SAndroid Build Coastguard Worker reset (); 244*2d1272b8SAndroid Build Coastguard Worker current = nullptr; 245*2d1272b8SAndroid Build Coastguard Worker } 246*2d1272b8SAndroid Build Coastguard Worker resethb_serialize_context_t247*2d1272b8SAndroid Build Coastguard Worker void reset () 248*2d1272b8SAndroid Build Coastguard Worker { 249*2d1272b8SAndroid Build Coastguard Worker this->errors = HB_SERIALIZE_ERROR_NONE; 250*2d1272b8SAndroid Build Coastguard Worker this->head = this->start; 251*2d1272b8SAndroid Build Coastguard Worker this->tail = this->end; 252*2d1272b8SAndroid Build Coastguard Worker this->zerocopy = nullptr; 253*2d1272b8SAndroid Build Coastguard Worker this->debug_depth = 0; 254*2d1272b8SAndroid Build Coastguard Worker 255*2d1272b8SAndroid Build Coastguard Worker fini (); 256*2d1272b8SAndroid Build Coastguard Worker this->packed.push (nullptr); 257*2d1272b8SAndroid Build Coastguard Worker this->packed_map.init (); 258*2d1272b8SAndroid Build Coastguard Worker } 259*2d1272b8SAndroid Build Coastguard Worker check_successhb_serialize_context_t260*2d1272b8SAndroid Build Coastguard Worker bool check_success (bool success, 261*2d1272b8SAndroid Build Coastguard Worker hb_serialize_error_t err_type = HB_SERIALIZE_ERROR_OTHER) 262*2d1272b8SAndroid Build Coastguard Worker { 263*2d1272b8SAndroid Build Coastguard Worker return successful () 264*2d1272b8SAndroid Build Coastguard Worker && (success || err (err_type)); 265*2d1272b8SAndroid Build Coastguard Worker } 266*2d1272b8SAndroid Build Coastguard Worker 267*2d1272b8SAndroid Build Coastguard Worker template <typename T1, typename T2> check_equalhb_serialize_context_t268*2d1272b8SAndroid Build Coastguard Worker bool check_equal (T1 &&v1, T2 &&v2, hb_serialize_error_t err_type) 269*2d1272b8SAndroid Build Coastguard Worker { 270*2d1272b8SAndroid Build Coastguard Worker if ((long long) v1 != (long long) v2) 271*2d1272b8SAndroid Build Coastguard Worker { 272*2d1272b8SAndroid Build Coastguard Worker return err (err_type); 273*2d1272b8SAndroid Build Coastguard Worker } 274*2d1272b8SAndroid Build Coastguard Worker return true; 275*2d1272b8SAndroid Build Coastguard Worker } 276*2d1272b8SAndroid Build Coastguard Worker 277*2d1272b8SAndroid Build Coastguard Worker template <typename T1, typename T2> check_assignhb_serialize_context_t278*2d1272b8SAndroid Build Coastguard Worker bool check_assign (T1 &v1, T2 &&v2, hb_serialize_error_t err_type) 279*2d1272b8SAndroid Build Coastguard Worker { return check_equal (v1 = v2, v2, err_type); } 280*2d1272b8SAndroid Build Coastguard Worker propagate_errorhb_serialize_context_t281*2d1272b8SAndroid Build Coastguard Worker template <typename T> bool propagate_error (T &&obj) 282*2d1272b8SAndroid Build Coastguard Worker { return check_success (!hb_deref (obj).in_error ()); } 283*2d1272b8SAndroid Build Coastguard Worker propagate_errorhb_serialize_context_t284*2d1272b8SAndroid Build Coastguard Worker template <typename T1, typename... Ts> bool propagate_error (T1 &&o1, Ts&&... os) 285*2d1272b8SAndroid Build Coastguard Worker { return propagate_error (std::forward<T1> (o1)) && 286*2d1272b8SAndroid Build Coastguard Worker propagate_error (std::forward<Ts> (os)...); } 287*2d1272b8SAndroid Build Coastguard Worker 288*2d1272b8SAndroid Build Coastguard Worker /* To be called around main operation. */ 289*2d1272b8SAndroid Build Coastguard Worker template <typename Type=char> 290*2d1272b8SAndroid Build Coastguard Worker __attribute__((returns_nonnull)) start_serializehb_serialize_context_t291*2d1272b8SAndroid Build Coastguard Worker Type *start_serialize () 292*2d1272b8SAndroid Build Coastguard Worker { 293*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, 294*2d1272b8SAndroid Build Coastguard Worker "start [%p..%p] (%lu bytes)", 295*2d1272b8SAndroid Build Coastguard Worker this->start, this->end, 296*2d1272b8SAndroid Build Coastguard Worker (unsigned long) (this->end - this->start)); 297*2d1272b8SAndroid Build Coastguard Worker 298*2d1272b8SAndroid Build Coastguard Worker assert (!current); 299*2d1272b8SAndroid Build Coastguard Worker return push<Type> (); 300*2d1272b8SAndroid Build Coastguard Worker } end_serializehb_serialize_context_t301*2d1272b8SAndroid Build Coastguard Worker void end_serialize () 302*2d1272b8SAndroid Build Coastguard Worker { 303*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, 304*2d1272b8SAndroid Build Coastguard Worker "end [%p..%p] serialized %u bytes; %s", 305*2d1272b8SAndroid Build Coastguard Worker this->start, this->end, 306*2d1272b8SAndroid Build Coastguard Worker (unsigned) (this->head - this->start), 307*2d1272b8SAndroid Build Coastguard Worker successful () ? "successful" : "UNSUCCESSFUL"); 308*2d1272b8SAndroid Build Coastguard Worker 309*2d1272b8SAndroid Build Coastguard Worker propagate_error (packed, packed_map); 310*2d1272b8SAndroid Build Coastguard Worker 311*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!current)) return; 312*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error())) 313*2d1272b8SAndroid Build Coastguard Worker { 314*2d1272b8SAndroid Build Coastguard Worker // Offset overflows that occur before link resolution cannot be handled 315*2d1272b8SAndroid Build Coastguard Worker // by repacking, so set a more general error. 316*2d1272b8SAndroid Build Coastguard Worker if (offset_overflow ()) err (HB_SERIALIZE_ERROR_OTHER); 317*2d1272b8SAndroid Build Coastguard Worker return; 318*2d1272b8SAndroid Build Coastguard Worker } 319*2d1272b8SAndroid Build Coastguard Worker 320*2d1272b8SAndroid Build Coastguard Worker assert (!current->next); 321*2d1272b8SAndroid Build Coastguard Worker 322*2d1272b8SAndroid Build Coastguard Worker /* Only "pack" if there exist other objects... Otherwise, don't bother. 323*2d1272b8SAndroid Build Coastguard Worker * Saves a move. */ 324*2d1272b8SAndroid Build Coastguard Worker if (packed.length <= 1) 325*2d1272b8SAndroid Build Coastguard Worker return; 326*2d1272b8SAndroid Build Coastguard Worker 327*2d1272b8SAndroid Build Coastguard Worker pop_pack (false); 328*2d1272b8SAndroid Build Coastguard Worker 329*2d1272b8SAndroid Build Coastguard Worker resolve_links (); 330*2d1272b8SAndroid Build Coastguard Worker } 331*2d1272b8SAndroid Build Coastguard Worker 332*2d1272b8SAndroid Build Coastguard Worker template <typename Type = void> 333*2d1272b8SAndroid Build Coastguard Worker __attribute__((returns_nonnull)) pushhb_serialize_context_t334*2d1272b8SAndroid Build Coastguard Worker Type *push () 335*2d1272b8SAndroid Build Coastguard Worker { 336*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return start_embed<Type> (); 337*2d1272b8SAndroid Build Coastguard Worker 338*2d1272b8SAndroid Build Coastguard Worker object_t *obj = object_pool.alloc (); 339*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!obj)) 340*2d1272b8SAndroid Build Coastguard Worker check_success (false); 341*2d1272b8SAndroid Build Coastguard Worker else 342*2d1272b8SAndroid Build Coastguard Worker { 343*2d1272b8SAndroid Build Coastguard Worker obj->head = head; 344*2d1272b8SAndroid Build Coastguard Worker obj->tail = tail; 345*2d1272b8SAndroid Build Coastguard Worker obj->next = current; 346*2d1272b8SAndroid Build Coastguard Worker current = obj; 347*2d1272b8SAndroid Build Coastguard Worker } 348*2d1272b8SAndroid Build Coastguard Worker return start_embed<Type> (); 349*2d1272b8SAndroid Build Coastguard Worker } pop_discardhb_serialize_context_t350*2d1272b8SAndroid Build Coastguard Worker void pop_discard () 351*2d1272b8SAndroid Build Coastguard Worker { 352*2d1272b8SAndroid Build Coastguard Worker object_t *obj = current; 353*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!obj)) return; 354*2d1272b8SAndroid Build Coastguard Worker // Allow cleanup when we've error'd out on int overflows which don't compromise 355*2d1272b8SAndroid Build Coastguard Worker // the serializer state. 356*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error() && !only_overflow ())) return; 357*2d1272b8SAndroid Build Coastguard Worker 358*2d1272b8SAndroid Build Coastguard Worker current = current->next; 359*2d1272b8SAndroid Build Coastguard Worker revert (zerocopy ? zerocopy : obj->head, obj->tail); 360*2d1272b8SAndroid Build Coastguard Worker zerocopy = nullptr; 361*2d1272b8SAndroid Build Coastguard Worker obj->fini (); 362*2d1272b8SAndroid Build Coastguard Worker object_pool.release (obj); 363*2d1272b8SAndroid Build Coastguard Worker } 364*2d1272b8SAndroid Build Coastguard Worker 365*2d1272b8SAndroid Build Coastguard Worker /* Set share to false when an object is unlikely shareable with others 366*2d1272b8SAndroid Build Coastguard Worker * so not worth an attempt, or a contiguous table is serialized as 367*2d1272b8SAndroid Build Coastguard Worker * multiple consecutive objects in the reverse order so can't be shared. 368*2d1272b8SAndroid Build Coastguard Worker */ pop_packhb_serialize_context_t369*2d1272b8SAndroid Build Coastguard Worker objidx_t pop_pack (bool share=true) 370*2d1272b8SAndroid Build Coastguard Worker { 371*2d1272b8SAndroid Build Coastguard Worker object_t *obj = current; 372*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!obj)) return 0; 373*2d1272b8SAndroid Build Coastguard Worker // Allow cleanup when we've error'd out on int overflows which don't compromise 374*2d1272b8SAndroid Build Coastguard Worker // the serializer state. 375*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error() && !only_overflow ())) return 0; 376*2d1272b8SAndroid Build Coastguard Worker 377*2d1272b8SAndroid Build Coastguard Worker current = current->next; 378*2d1272b8SAndroid Build Coastguard Worker obj->tail = head; 379*2d1272b8SAndroid Build Coastguard Worker obj->next = nullptr; 380*2d1272b8SAndroid Build Coastguard Worker assert (obj->head <= obj->tail); 381*2d1272b8SAndroid Build Coastguard Worker unsigned len = obj->tail - obj->head; 382*2d1272b8SAndroid Build Coastguard Worker head = zerocopy ? zerocopy : obj->head; /* Rewind head. */ 383*2d1272b8SAndroid Build Coastguard Worker bool was_zerocopy = zerocopy; 384*2d1272b8SAndroid Build Coastguard Worker zerocopy = nullptr; 385*2d1272b8SAndroid Build Coastguard Worker 386*2d1272b8SAndroid Build Coastguard Worker if (!len) 387*2d1272b8SAndroid Build Coastguard Worker { 388*2d1272b8SAndroid Build Coastguard Worker assert (!obj->real_links.length); 389*2d1272b8SAndroid Build Coastguard Worker assert (!obj->virtual_links.length); 390*2d1272b8SAndroid Build Coastguard Worker return 0; 391*2d1272b8SAndroid Build Coastguard Worker } 392*2d1272b8SAndroid Build Coastguard Worker 393*2d1272b8SAndroid Build Coastguard Worker objidx_t objidx; 394*2d1272b8SAndroid Build Coastguard Worker uint32_t hash = 0; 395*2d1272b8SAndroid Build Coastguard Worker if (share) 396*2d1272b8SAndroid Build Coastguard Worker { 397*2d1272b8SAndroid Build Coastguard Worker hash = hb_hash (obj); 398*2d1272b8SAndroid Build Coastguard Worker objidx = packed_map.get_with_hash (obj, hash); 399*2d1272b8SAndroid Build Coastguard Worker if (objidx) 400*2d1272b8SAndroid Build Coastguard Worker { 401*2d1272b8SAndroid Build Coastguard Worker merge_virtual_links (obj, objidx); 402*2d1272b8SAndroid Build Coastguard Worker obj->fini (); 403*2d1272b8SAndroid Build Coastguard Worker return objidx; 404*2d1272b8SAndroid Build Coastguard Worker } 405*2d1272b8SAndroid Build Coastguard Worker } 406*2d1272b8SAndroid Build Coastguard Worker 407*2d1272b8SAndroid Build Coastguard Worker tail -= len; 408*2d1272b8SAndroid Build Coastguard Worker if (was_zerocopy) 409*2d1272b8SAndroid Build Coastguard Worker assert (tail == obj->head); 410*2d1272b8SAndroid Build Coastguard Worker else 411*2d1272b8SAndroid Build Coastguard Worker memmove (tail, obj->head, len); 412*2d1272b8SAndroid Build Coastguard Worker 413*2d1272b8SAndroid Build Coastguard Worker obj->head = tail; 414*2d1272b8SAndroid Build Coastguard Worker obj->tail = tail + len; 415*2d1272b8SAndroid Build Coastguard Worker 416*2d1272b8SAndroid Build Coastguard Worker packed.push (obj); 417*2d1272b8SAndroid Build Coastguard Worker 418*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!propagate_error (packed))) 419*2d1272b8SAndroid Build Coastguard Worker { 420*2d1272b8SAndroid Build Coastguard Worker /* Obj wasn't successfully added to packed, so clean it up otherwise its 421*2d1272b8SAndroid Build Coastguard Worker * links will be leaked. When we use constructor/destructors properly, we 422*2d1272b8SAndroid Build Coastguard Worker * can remove these. */ 423*2d1272b8SAndroid Build Coastguard Worker obj->fini (); 424*2d1272b8SAndroid Build Coastguard Worker return 0; 425*2d1272b8SAndroid Build Coastguard Worker } 426*2d1272b8SAndroid Build Coastguard Worker 427*2d1272b8SAndroid Build Coastguard Worker objidx = packed.length - 1; 428*2d1272b8SAndroid Build Coastguard Worker 429*2d1272b8SAndroid Build Coastguard Worker if (share) packed_map.set_with_hash (obj, hash, objidx); 430*2d1272b8SAndroid Build Coastguard Worker propagate_error (packed_map); 431*2d1272b8SAndroid Build Coastguard Worker 432*2d1272b8SAndroid Build Coastguard Worker return objidx; 433*2d1272b8SAndroid Build Coastguard Worker } 434*2d1272b8SAndroid Build Coastguard Worker reverthb_serialize_context_t435*2d1272b8SAndroid Build Coastguard Worker void revert (snapshot_t snap) 436*2d1272b8SAndroid Build Coastguard Worker { 437*2d1272b8SAndroid Build Coastguard Worker // Overflows that happened after the snapshot will be erased by the revert. 438*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error () && !only_overflow ())) return; 439*2d1272b8SAndroid Build Coastguard Worker assert (snap.current == current); 440*2d1272b8SAndroid Build Coastguard Worker if (current) 441*2d1272b8SAndroid Build Coastguard Worker { 442*2d1272b8SAndroid Build Coastguard Worker current->real_links.shrink (snap.num_real_links); 443*2d1272b8SAndroid Build Coastguard Worker current->virtual_links.shrink (snap.num_virtual_links); 444*2d1272b8SAndroid Build Coastguard Worker } 445*2d1272b8SAndroid Build Coastguard Worker errors = snap.errors; 446*2d1272b8SAndroid Build Coastguard Worker revert (snap.head, snap.tail); 447*2d1272b8SAndroid Build Coastguard Worker } 448*2d1272b8SAndroid Build Coastguard Worker reverthb_serialize_context_t449*2d1272b8SAndroid Build Coastguard Worker void revert (char *snap_head, 450*2d1272b8SAndroid Build Coastguard Worker char *snap_tail) 451*2d1272b8SAndroid Build Coastguard Worker { 452*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return; 453*2d1272b8SAndroid Build Coastguard Worker assert (snap_head <= head); 454*2d1272b8SAndroid Build Coastguard Worker assert (tail <= snap_tail); 455*2d1272b8SAndroid Build Coastguard Worker head = snap_head; 456*2d1272b8SAndroid Build Coastguard Worker tail = snap_tail; 457*2d1272b8SAndroid Build Coastguard Worker discard_stale_objects (); 458*2d1272b8SAndroid Build Coastguard Worker } 459*2d1272b8SAndroid Build Coastguard Worker discard_stale_objectshb_serialize_context_t460*2d1272b8SAndroid Build Coastguard Worker void discard_stale_objects () 461*2d1272b8SAndroid Build Coastguard Worker { 462*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return; 463*2d1272b8SAndroid Build Coastguard Worker while (packed.length > 1 && 464*2d1272b8SAndroid Build Coastguard Worker packed.tail ()->head < tail) 465*2d1272b8SAndroid Build Coastguard Worker { 466*2d1272b8SAndroid Build Coastguard Worker packed_map.del (packed.tail ()); 467*2d1272b8SAndroid Build Coastguard Worker assert (!packed.tail ()->next); 468*2d1272b8SAndroid Build Coastguard Worker packed.tail ()->fini (); 469*2d1272b8SAndroid Build Coastguard Worker packed.pop (); 470*2d1272b8SAndroid Build Coastguard Worker } 471*2d1272b8SAndroid Build Coastguard Worker if (packed.length > 1) 472*2d1272b8SAndroid Build Coastguard Worker assert (packed.tail ()->head == tail); 473*2d1272b8SAndroid Build Coastguard Worker } 474*2d1272b8SAndroid Build Coastguard Worker 475*2d1272b8SAndroid Build Coastguard Worker // Adds a virtual link from the current object to objidx. A virtual link is not associated with 476*2d1272b8SAndroid Build Coastguard Worker // an actual offset field. They are solely used to enforce ordering constraints between objects. 477*2d1272b8SAndroid Build Coastguard Worker // Adding a virtual link from object a to object b will ensure that object b is always packed after 478*2d1272b8SAndroid Build Coastguard Worker // object a in the final serialized order. 479*2d1272b8SAndroid Build Coastguard Worker // 480*2d1272b8SAndroid Build Coastguard Worker // This is useful in certain situations where there needs to be a specific ordering in the 481*2d1272b8SAndroid Build Coastguard Worker // final serialization. Such as when platform bugs require certain orderings, or to provide 482*2d1272b8SAndroid Build Coastguard Worker // guidance to the repacker for better offset overflow resolution. add_virtual_linkhb_serialize_context_t483*2d1272b8SAndroid Build Coastguard Worker void add_virtual_link (objidx_t objidx) 484*2d1272b8SAndroid Build Coastguard Worker { 485*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return; 486*2d1272b8SAndroid Build Coastguard Worker 487*2d1272b8SAndroid Build Coastguard Worker if (!objidx) 488*2d1272b8SAndroid Build Coastguard Worker return; 489*2d1272b8SAndroid Build Coastguard Worker 490*2d1272b8SAndroid Build Coastguard Worker assert (current); 491*2d1272b8SAndroid Build Coastguard Worker 492*2d1272b8SAndroid Build Coastguard Worker if (!current->add_virtual_link(objidx)) 493*2d1272b8SAndroid Build Coastguard Worker err (HB_SERIALIZE_ERROR_OTHER); 494*2d1272b8SAndroid Build Coastguard Worker } 495*2d1272b8SAndroid Build Coastguard Worker last_added_child_indexhb_serialize_context_t496*2d1272b8SAndroid Build Coastguard Worker objidx_t last_added_child_index() const { 497*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return (objidx_t) -1; 498*2d1272b8SAndroid Build Coastguard Worker 499*2d1272b8SAndroid Build Coastguard Worker assert (current); 500*2d1272b8SAndroid Build Coastguard Worker if (!bool(current->real_links)) { 501*2d1272b8SAndroid Build Coastguard Worker return (objidx_t) -1; 502*2d1272b8SAndroid Build Coastguard Worker } 503*2d1272b8SAndroid Build Coastguard Worker 504*2d1272b8SAndroid Build Coastguard Worker return current->real_links[current->real_links.length - 1].objidx; 505*2d1272b8SAndroid Build Coastguard Worker } 506*2d1272b8SAndroid Build Coastguard Worker 507*2d1272b8SAndroid Build Coastguard Worker // For the current object ensure that the sub-table bytes for child objidx are always placed 508*2d1272b8SAndroid Build Coastguard Worker // after the subtable bytes for any other existing children. This only ensures that the 509*2d1272b8SAndroid Build Coastguard Worker // repacker will not move the target subtable before the other children 510*2d1272b8SAndroid Build Coastguard Worker // (by adding virtual links). It is up to the caller to ensure the initial serialization 511*2d1272b8SAndroid Build Coastguard Worker // order is correct. repack_lasthb_serialize_context_t512*2d1272b8SAndroid Build Coastguard Worker void repack_last(objidx_t objidx) { 513*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return; 514*2d1272b8SAndroid Build Coastguard Worker 515*2d1272b8SAndroid Build Coastguard Worker if (!objidx) 516*2d1272b8SAndroid Build Coastguard Worker return; 517*2d1272b8SAndroid Build Coastguard Worker 518*2d1272b8SAndroid Build Coastguard Worker assert (current); 519*2d1272b8SAndroid Build Coastguard Worker for (auto& l : current->real_links) { 520*2d1272b8SAndroid Build Coastguard Worker if (l.objidx == objidx) { 521*2d1272b8SAndroid Build Coastguard Worker continue; 522*2d1272b8SAndroid Build Coastguard Worker } 523*2d1272b8SAndroid Build Coastguard Worker 524*2d1272b8SAndroid Build Coastguard Worker packed[l.objidx]->add_virtual_link(objidx); 525*2d1272b8SAndroid Build Coastguard Worker } 526*2d1272b8SAndroid Build Coastguard Worker } 527*2d1272b8SAndroid Build Coastguard Worker 528*2d1272b8SAndroid Build Coastguard Worker template <typename T> add_linkhb_serialize_context_t529*2d1272b8SAndroid Build Coastguard Worker void add_link (T &ofs, objidx_t objidx, 530*2d1272b8SAndroid Build Coastguard Worker whence_t whence = Head, 531*2d1272b8SAndroid Build Coastguard Worker unsigned bias = 0) 532*2d1272b8SAndroid Build Coastguard Worker { 533*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return; 534*2d1272b8SAndroid Build Coastguard Worker 535*2d1272b8SAndroid Build Coastguard Worker if (!objidx) 536*2d1272b8SAndroid Build Coastguard Worker return; 537*2d1272b8SAndroid Build Coastguard Worker 538*2d1272b8SAndroid Build Coastguard Worker assert (current); 539*2d1272b8SAndroid Build Coastguard Worker assert (current->head <= (const char *) &ofs); 540*2d1272b8SAndroid Build Coastguard Worker 541*2d1272b8SAndroid Build Coastguard Worker auto& link = *current->real_links.push (); 542*2d1272b8SAndroid Build Coastguard Worker if (current->real_links.in_error ()) 543*2d1272b8SAndroid Build Coastguard Worker err (HB_SERIALIZE_ERROR_OTHER); 544*2d1272b8SAndroid Build Coastguard Worker 545*2d1272b8SAndroid Build Coastguard Worker link.width = sizeof (T); 546*2d1272b8SAndroid Build Coastguard Worker link.objidx = objidx; 547*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!sizeof (T))) 548*2d1272b8SAndroid Build Coastguard Worker { 549*2d1272b8SAndroid Build Coastguard Worker // This link is not associated with an actual offset and exists merely to enforce 550*2d1272b8SAndroid Build Coastguard Worker // an ordering constraint. 551*2d1272b8SAndroid Build Coastguard Worker link.is_signed = 0; 552*2d1272b8SAndroid Build Coastguard Worker link.whence = 0; 553*2d1272b8SAndroid Build Coastguard Worker link.position = 0; 554*2d1272b8SAndroid Build Coastguard Worker link.bias = 0; 555*2d1272b8SAndroid Build Coastguard Worker return; 556*2d1272b8SAndroid Build Coastguard Worker } 557*2d1272b8SAndroid Build Coastguard Worker 558*2d1272b8SAndroid Build Coastguard Worker link.is_signed = std::is_signed<hb_unwrap_type (T)>::value; 559*2d1272b8SAndroid Build Coastguard Worker link.whence = (unsigned) whence; 560*2d1272b8SAndroid Build Coastguard Worker link.position = (const char *) &ofs - current->head; 561*2d1272b8SAndroid Build Coastguard Worker link.bias = bias; 562*2d1272b8SAndroid Build Coastguard Worker } 563*2d1272b8SAndroid Build Coastguard Worker to_biashb_serialize_context_t564*2d1272b8SAndroid Build Coastguard Worker unsigned to_bias (const void *base) const 565*2d1272b8SAndroid Build Coastguard Worker { 566*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return 0; 567*2d1272b8SAndroid Build Coastguard Worker if (!base) return 0; 568*2d1272b8SAndroid Build Coastguard Worker assert (current); 569*2d1272b8SAndroid Build Coastguard Worker assert (current->head <= (const char *) base); 570*2d1272b8SAndroid Build Coastguard Worker return (const char *) base - current->head; 571*2d1272b8SAndroid Build Coastguard Worker } 572*2d1272b8SAndroid Build Coastguard Worker resolve_linkshb_serialize_context_t573*2d1272b8SAndroid Build Coastguard Worker void resolve_links () 574*2d1272b8SAndroid Build Coastguard Worker { 575*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return; 576*2d1272b8SAndroid Build Coastguard Worker 577*2d1272b8SAndroid Build Coastguard Worker assert (!current); 578*2d1272b8SAndroid Build Coastguard Worker assert (packed.length > 1); 579*2d1272b8SAndroid Build Coastguard Worker 580*2d1272b8SAndroid Build Coastguard Worker for (const object_t* parent : ++hb_iter (packed)) 581*2d1272b8SAndroid Build Coastguard Worker for (const object_t::link_t &link : parent->real_links) 582*2d1272b8SAndroid Build Coastguard Worker { 583*2d1272b8SAndroid Build Coastguard Worker const object_t* child = packed[link.objidx]; 584*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; } 585*2d1272b8SAndroid Build Coastguard Worker unsigned offset = 0; 586*2d1272b8SAndroid Build Coastguard Worker switch ((whence_t) link.whence) { 587*2d1272b8SAndroid Build Coastguard Worker case Head: offset = child->head - parent->head; break; 588*2d1272b8SAndroid Build Coastguard Worker case Tail: offset = child->head - parent->tail; break; 589*2d1272b8SAndroid Build Coastguard Worker case Absolute: offset = (head - start) + (child->head - tail); break; 590*2d1272b8SAndroid Build Coastguard Worker } 591*2d1272b8SAndroid Build Coastguard Worker 592*2d1272b8SAndroid Build Coastguard Worker assert (offset >= link.bias); 593*2d1272b8SAndroid Build Coastguard Worker offset -= link.bias; 594*2d1272b8SAndroid Build Coastguard Worker if (link.is_signed) 595*2d1272b8SAndroid Build Coastguard Worker { 596*2d1272b8SAndroid Build Coastguard Worker assert (link.width == 2 || link.width == 4); 597*2d1272b8SAndroid Build Coastguard Worker if (link.width == 4) 598*2d1272b8SAndroid Build Coastguard Worker assign_offset<int32_t> (parent, link, offset); 599*2d1272b8SAndroid Build Coastguard Worker else 600*2d1272b8SAndroid Build Coastguard Worker assign_offset<int16_t> (parent, link, offset); 601*2d1272b8SAndroid Build Coastguard Worker } 602*2d1272b8SAndroid Build Coastguard Worker else 603*2d1272b8SAndroid Build Coastguard Worker { 604*2d1272b8SAndroid Build Coastguard Worker assert (link.width == 2 || link.width == 3 || link.width == 4); 605*2d1272b8SAndroid Build Coastguard Worker if (link.width == 4) 606*2d1272b8SAndroid Build Coastguard Worker assign_offset<uint32_t> (parent, link, offset); 607*2d1272b8SAndroid Build Coastguard Worker else if (link.width == 3) 608*2d1272b8SAndroid Build Coastguard Worker assign_offset<uint32_t, 3> (parent, link, offset); 609*2d1272b8SAndroid Build Coastguard Worker else 610*2d1272b8SAndroid Build Coastguard Worker assign_offset<uint16_t> (parent, link, offset); 611*2d1272b8SAndroid Build Coastguard Worker } 612*2d1272b8SAndroid Build Coastguard Worker } 613*2d1272b8SAndroid Build Coastguard Worker } 614*2d1272b8SAndroid Build Coastguard Worker lengthhb_serialize_context_t615*2d1272b8SAndroid Build Coastguard Worker unsigned int length () const 616*2d1272b8SAndroid Build Coastguard Worker { 617*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!current)) return 0; 618*2d1272b8SAndroid Build Coastguard Worker return this->head - current->head; 619*2d1272b8SAndroid Build Coastguard Worker } 620*2d1272b8SAndroid Build Coastguard Worker alignhb_serialize_context_t621*2d1272b8SAndroid Build Coastguard Worker void align (unsigned int alignment) 622*2d1272b8SAndroid Build Coastguard Worker { 623*2d1272b8SAndroid Build Coastguard Worker unsigned int l = length () % alignment; 624*2d1272b8SAndroid Build Coastguard Worker if (l) 625*2d1272b8SAndroid Build Coastguard Worker (void) allocate_size<void> (alignment - l); 626*2d1272b8SAndroid Build Coastguard Worker } 627*2d1272b8SAndroid Build Coastguard Worker 628*2d1272b8SAndroid Build Coastguard Worker template <typename Type = void> 629*2d1272b8SAndroid Build Coastguard Worker __attribute__((returns_nonnull)) start_embedhb_serialize_context_t630*2d1272b8SAndroid Build Coastguard Worker Type *start_embed (const Type *obj HB_UNUSED = nullptr) const 631*2d1272b8SAndroid Build Coastguard Worker { return reinterpret_cast<Type *> (this->head); } 632*2d1272b8SAndroid Build Coastguard Worker template <typename Type> 633*2d1272b8SAndroid Build Coastguard Worker __attribute__((returns_nonnull)) start_embedhb_serialize_context_t634*2d1272b8SAndroid Build Coastguard Worker Type *start_embed (const Type &obj) const 635*2d1272b8SAndroid Build Coastguard Worker { return start_embed (std::addressof (obj)); } 636*2d1272b8SAndroid Build Coastguard Worker errhb_serialize_context_t637*2d1272b8SAndroid Build Coastguard Worker bool err (hb_serialize_error_t err_type) 638*2d1272b8SAndroid Build Coastguard Worker { 639*2d1272b8SAndroid Build Coastguard Worker return !bool ((errors = (errors | err_type))); 640*2d1272b8SAndroid Build Coastguard Worker } 641*2d1272b8SAndroid Build Coastguard Worker start_zerocopyhb_serialize_context_t642*2d1272b8SAndroid Build Coastguard Worker bool start_zerocopy (size_t size) 643*2d1272b8SAndroid Build Coastguard Worker { 644*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return false; 645*2d1272b8SAndroid Build Coastguard Worker 646*2d1272b8SAndroid Build Coastguard Worker if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size))) 647*2d1272b8SAndroid Build Coastguard Worker { 648*2d1272b8SAndroid Build Coastguard Worker err (HB_SERIALIZE_ERROR_OUT_OF_ROOM); 649*2d1272b8SAndroid Build Coastguard Worker return false; 650*2d1272b8SAndroid Build Coastguard Worker } 651*2d1272b8SAndroid Build Coastguard Worker 652*2d1272b8SAndroid Build Coastguard Worker assert (!this->zerocopy); 653*2d1272b8SAndroid Build Coastguard Worker this->zerocopy = this->head; 654*2d1272b8SAndroid Build Coastguard Worker 655*2d1272b8SAndroid Build Coastguard Worker assert (this->current->head == this->head); 656*2d1272b8SAndroid Build Coastguard Worker this->current->head = this->current->tail = this->head = this->tail - size; 657*2d1272b8SAndroid Build Coastguard Worker return true; 658*2d1272b8SAndroid Build Coastguard Worker } 659*2d1272b8SAndroid Build Coastguard Worker 660*2d1272b8SAndroid Build Coastguard Worker template <typename Type> 661*2d1272b8SAndroid Build Coastguard Worker HB_NODISCARD allocate_sizehb_serialize_context_t662*2d1272b8SAndroid Build Coastguard Worker Type *allocate_size (size_t size, bool clear = true) 663*2d1272b8SAndroid Build Coastguard Worker { 664*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return nullptr; 665*2d1272b8SAndroid Build Coastguard Worker 666*2d1272b8SAndroid Build Coastguard Worker if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size))) 667*2d1272b8SAndroid Build Coastguard Worker { 668*2d1272b8SAndroid Build Coastguard Worker err (HB_SERIALIZE_ERROR_OUT_OF_ROOM); 669*2d1272b8SAndroid Build Coastguard Worker return nullptr; 670*2d1272b8SAndroid Build Coastguard Worker } 671*2d1272b8SAndroid Build Coastguard Worker if (clear) 672*2d1272b8SAndroid Build Coastguard Worker hb_memset (this->head, 0, size); 673*2d1272b8SAndroid Build Coastguard Worker char *ret = this->head; 674*2d1272b8SAndroid Build Coastguard Worker this->head += size; 675*2d1272b8SAndroid Build Coastguard Worker return reinterpret_cast<Type *> (ret); 676*2d1272b8SAndroid Build Coastguard Worker } 677*2d1272b8SAndroid Build Coastguard Worker 678*2d1272b8SAndroid Build Coastguard Worker template <typename Type> allocate_minhb_serialize_context_t679*2d1272b8SAndroid Build Coastguard Worker Type *allocate_min () 680*2d1272b8SAndroid Build Coastguard Worker { return this->allocate_size<Type> (Type::min_size); } 681*2d1272b8SAndroid Build Coastguard Worker 682*2d1272b8SAndroid Build Coastguard Worker template <typename Type> 683*2d1272b8SAndroid Build Coastguard Worker HB_NODISCARD embedhb_serialize_context_t684*2d1272b8SAndroid Build Coastguard Worker Type *embed (const Type *obj) 685*2d1272b8SAndroid Build Coastguard Worker { 686*2d1272b8SAndroid Build Coastguard Worker unsigned int size = obj->get_size (); 687*2d1272b8SAndroid Build Coastguard Worker Type *ret = this->allocate_size<Type> (size, false); 688*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!ret)) return nullptr; 689*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (ret, obj, size); 690*2d1272b8SAndroid Build Coastguard Worker return ret; 691*2d1272b8SAndroid Build Coastguard Worker } 692*2d1272b8SAndroid Build Coastguard Worker template <typename Type> 693*2d1272b8SAndroid Build Coastguard Worker HB_NODISCARD embedhb_serialize_context_t694*2d1272b8SAndroid Build Coastguard Worker Type *embed (const Type &obj) 695*2d1272b8SAndroid Build Coastguard Worker { return embed (std::addressof (obj)); } embedhb_serialize_context_t696*2d1272b8SAndroid Build Coastguard Worker char *embed (const char *obj, unsigned size) 697*2d1272b8SAndroid Build Coastguard Worker { 698*2d1272b8SAndroid Build Coastguard Worker char *ret = this->allocate_size<char> (size, false); 699*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!ret)) return nullptr; 700*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (ret, obj, size); 701*2d1272b8SAndroid Build Coastguard Worker return ret; 702*2d1272b8SAndroid Build Coastguard Worker } 703*2d1272b8SAndroid Build Coastguard Worker 704*2d1272b8SAndroid Build Coastguard Worker template <typename Type, typename ...Ts> auto _copyhb_serialize_context_t705*2d1272b8SAndroid Build Coastguard Worker _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN 706*2d1272b8SAndroid Build Coastguard Worker (Type *, src.copy (this, std::forward<Ts> (ds)...)) 707*2d1272b8SAndroid Build Coastguard Worker 708*2d1272b8SAndroid Build Coastguard Worker template <typename Type> auto 709*2d1272b8SAndroid Build Coastguard Worker _copy (const Type &src, hb_priority<0>) -> decltype (&(hb_declval<Type> () = src)) 710*2d1272b8SAndroid Build Coastguard Worker { 711*2d1272b8SAndroid Build Coastguard Worker Type *ret = this->allocate_size<Type> (sizeof (Type)); 712*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!ret)) return nullptr; 713*2d1272b8SAndroid Build Coastguard Worker *ret = src; 714*2d1272b8SAndroid Build Coastguard Worker return ret; 715*2d1272b8SAndroid Build Coastguard Worker } 716*2d1272b8SAndroid Build Coastguard Worker 717*2d1272b8SAndroid Build Coastguard Worker /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data 718*2d1272b8SAndroid Build Coastguard Worker * instead of hb_memcpy(). */ 719*2d1272b8SAndroid Build Coastguard Worker template <typename Type, typename ...Ts> copyhb_serialize_context_t720*2d1272b8SAndroid Build Coastguard Worker Type *copy (const Type &src, Ts&&... ds) 721*2d1272b8SAndroid Build Coastguard Worker { return _copy (src, hb_prioritize, std::forward<Ts> (ds)...); } 722*2d1272b8SAndroid Build Coastguard Worker template <typename Type, typename ...Ts> copyhb_serialize_context_t723*2d1272b8SAndroid Build Coastguard Worker Type *copy (const Type *src, Ts&&... ds) 724*2d1272b8SAndroid Build Coastguard Worker { return copy (*src, std::forward<Ts> (ds)...); } 725*2d1272b8SAndroid Build Coastguard Worker 726*2d1272b8SAndroid Build Coastguard Worker template<typename Iterator, 727*2d1272b8SAndroid Build Coastguard Worker hb_requires (hb_is_iterator (Iterator)), 728*2d1272b8SAndroid Build Coastguard Worker typename ...Ts> copy_allhb_serialize_context_t729*2d1272b8SAndroid Build Coastguard Worker void copy_all (Iterator it, Ts&&... ds) 730*2d1272b8SAndroid Build Coastguard Worker { for (decltype (*it) _ : it) copy (_, std::forward<Ts> (ds)...); } 731*2d1272b8SAndroid Build Coastguard Worker 732*2d1272b8SAndroid Build Coastguard Worker template <typename Type> operator <<hb_serialize_context_t733*2d1272b8SAndroid Build Coastguard Worker hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; } 734*2d1272b8SAndroid Build Coastguard Worker 735*2d1272b8SAndroid Build Coastguard Worker template <typename Type> extend_sizehb_serialize_context_t736*2d1272b8SAndroid Build Coastguard Worker Type *extend_size (Type *obj, size_t size, bool clear = true) 737*2d1272b8SAndroid Build Coastguard Worker { 738*2d1272b8SAndroid Build Coastguard Worker if (unlikely (in_error ())) return nullptr; 739*2d1272b8SAndroid Build Coastguard Worker 740*2d1272b8SAndroid Build Coastguard Worker assert (this->start <= (char *) obj); 741*2d1272b8SAndroid Build Coastguard Worker assert ((char *) obj <= this->head); 742*2d1272b8SAndroid Build Coastguard Worker assert ((size_t) (this->head - (char *) obj) <= size); 743*2d1272b8SAndroid Build Coastguard Worker if (unlikely (((char *) obj + size < (char *) obj) || 744*2d1272b8SAndroid Build Coastguard Worker !this->allocate_size<Type> (((char *) obj) + size - this->head, clear))) return nullptr; 745*2d1272b8SAndroid Build Coastguard Worker return reinterpret_cast<Type *> (obj); 746*2d1272b8SAndroid Build Coastguard Worker } 747*2d1272b8SAndroid Build Coastguard Worker template <typename Type> extend_sizehb_serialize_context_t748*2d1272b8SAndroid Build Coastguard Worker Type *extend_size (Type &obj, size_t size, bool clear = true) 749*2d1272b8SAndroid Build Coastguard Worker { return extend_size (std::addressof (obj), size, clear); } 750*2d1272b8SAndroid Build Coastguard Worker 751*2d1272b8SAndroid Build Coastguard Worker template <typename Type> extend_minhb_serialize_context_t752*2d1272b8SAndroid Build Coastguard Worker Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); } 753*2d1272b8SAndroid Build Coastguard Worker template <typename Type> extend_minhb_serialize_context_t754*2d1272b8SAndroid Build Coastguard Worker Type *extend_min (Type &obj) { return extend_min (std::addressof (obj)); } 755*2d1272b8SAndroid Build Coastguard Worker 756*2d1272b8SAndroid Build Coastguard Worker template <typename Type, typename ...Ts> extendhb_serialize_context_t757*2d1272b8SAndroid Build Coastguard Worker Type *extend (Type *obj, Ts&&... ds) 758*2d1272b8SAndroid Build Coastguard Worker { return extend_size (obj, obj->get_size (std::forward<Ts> (ds)...)); } 759*2d1272b8SAndroid Build Coastguard Worker template <typename Type, typename ...Ts> extendhb_serialize_context_t760*2d1272b8SAndroid Build Coastguard Worker Type *extend (Type &obj, Ts&&... ds) 761*2d1272b8SAndroid Build Coastguard Worker { return extend (std::addressof (obj), std::forward<Ts> (ds)...); } 762*2d1272b8SAndroid Build Coastguard Worker 763*2d1272b8SAndroid Build Coastguard Worker /* Output routines. */ copy_byteshb_serialize_context_t764*2d1272b8SAndroid Build Coastguard Worker hb_bytes_t copy_bytes () const 765*2d1272b8SAndroid Build Coastguard Worker { 766*2d1272b8SAndroid Build Coastguard Worker assert (successful ()); 767*2d1272b8SAndroid Build Coastguard Worker /* Copy both items from head side and tail side... */ 768*2d1272b8SAndroid Build Coastguard Worker unsigned int len = (this->head - this->start) 769*2d1272b8SAndroid Build Coastguard Worker + (this->end - this->tail); 770*2d1272b8SAndroid Build Coastguard Worker 771*2d1272b8SAndroid Build Coastguard Worker // If len is zero don't hb_malloc as the memory won't get properly 772*2d1272b8SAndroid Build Coastguard Worker // cleaned up later. 773*2d1272b8SAndroid Build Coastguard Worker if (!len) return hb_bytes_t (); 774*2d1272b8SAndroid Build Coastguard Worker 775*2d1272b8SAndroid Build Coastguard Worker char *p = (char *) hb_malloc (len); 776*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!p)) return hb_bytes_t (); 777*2d1272b8SAndroid Build Coastguard Worker 778*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (p, this->start, this->head - this->start); 779*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (p + (this->head - this->start), this->tail, this->end - this->tail); 780*2d1272b8SAndroid Build Coastguard Worker return hb_bytes_t (p, len); 781*2d1272b8SAndroid Build Coastguard Worker } 782*2d1272b8SAndroid Build Coastguard Worker template <typename Type> copyhb_serialize_context_t783*2d1272b8SAndroid Build Coastguard Worker Type *copy () const 784*2d1272b8SAndroid Build Coastguard Worker { return reinterpret_cast<Type *> ((char *) copy_bytes ().arrayZ); } copy_blobhb_serialize_context_t785*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *copy_blob () const 786*2d1272b8SAndroid Build Coastguard Worker { 787*2d1272b8SAndroid Build Coastguard Worker hb_bytes_t b = copy_bytes (); 788*2d1272b8SAndroid Build Coastguard Worker return hb_blob_create (b.arrayZ, b.length, 789*2d1272b8SAndroid Build Coastguard Worker HB_MEMORY_MODE_WRITABLE, 790*2d1272b8SAndroid Build Coastguard Worker (char *) b.arrayZ, hb_free); 791*2d1272b8SAndroid Build Coastguard Worker } 792*2d1272b8SAndroid Build Coastguard Worker object_graphhb_serialize_context_t793*2d1272b8SAndroid Build Coastguard Worker const hb_vector_t<object_t *>& object_graph() const 794*2d1272b8SAndroid Build Coastguard Worker { return packed; } 795*2d1272b8SAndroid Build Coastguard Worker 796*2d1272b8SAndroid Build Coastguard Worker private: 797*2d1272b8SAndroid Build Coastguard Worker template <typename T, unsigned Size = sizeof (T)> assign_offsethb_serialize_context_t798*2d1272b8SAndroid Build Coastguard Worker void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) 799*2d1272b8SAndroid Build Coastguard Worker { 800*2d1272b8SAndroid Build Coastguard Worker auto &off = * ((BEInt<T, Size> *) (parent->head + link.position)); 801*2d1272b8SAndroid Build Coastguard Worker assert (0 == off); 802*2d1272b8SAndroid Build Coastguard Worker check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); 803*2d1272b8SAndroid Build Coastguard Worker } 804*2d1272b8SAndroid Build Coastguard Worker 805*2d1272b8SAndroid Build Coastguard Worker public: 806*2d1272b8SAndroid Build Coastguard Worker char *start, *head, *tail, *end, *zerocopy; 807*2d1272b8SAndroid Build Coastguard Worker unsigned int debug_depth; 808*2d1272b8SAndroid Build Coastguard Worker hb_serialize_error_t errors; 809*2d1272b8SAndroid Build Coastguard Worker 810*2d1272b8SAndroid Build Coastguard Worker private: 811*2d1272b8SAndroid Build Coastguard Worker merge_virtual_linkshb_serialize_context_t812*2d1272b8SAndroid Build Coastguard Worker void merge_virtual_links (const object_t* from, objidx_t to_idx) { 813*2d1272b8SAndroid Build Coastguard Worker object_t* to = packed[to_idx]; 814*2d1272b8SAndroid Build Coastguard Worker for (const auto& l : from->virtual_links) { 815*2d1272b8SAndroid Build Coastguard Worker to->virtual_links.push (l); 816*2d1272b8SAndroid Build Coastguard Worker } 817*2d1272b8SAndroid Build Coastguard Worker } 818*2d1272b8SAndroid Build Coastguard Worker 819*2d1272b8SAndroid Build Coastguard Worker /* Object memory pool. */ 820*2d1272b8SAndroid Build Coastguard Worker hb_pool_t<object_t> object_pool; 821*2d1272b8SAndroid Build Coastguard Worker 822*2d1272b8SAndroid Build Coastguard Worker /* Stack of currently under construction objects. */ 823*2d1272b8SAndroid Build Coastguard Worker object_t *current; 824*2d1272b8SAndroid Build Coastguard Worker 825*2d1272b8SAndroid Build Coastguard Worker /* Stack of packed objects. Object 0 is always nil object. */ 826*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<object_t *> packed; 827*2d1272b8SAndroid Build Coastguard Worker 828*2d1272b8SAndroid Build Coastguard Worker /* Map view of packed objects. */ 829*2d1272b8SAndroid Build Coastguard Worker hb_hashmap_t<const object_t *, objidx_t> packed_map; 830*2d1272b8SAndroid Build Coastguard Worker }; 831*2d1272b8SAndroid Build Coastguard Worker 832*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_SERIALIZE_HH */ 833