Home | History | Annotate | Download | only in layout
      1 /*
      2  * -*- c++ -*-
      3  *
      4  * (C) Copyright IBM Corp. and others 2013 - All Rights Reserved
      5  *
      6  * Range checking
      7  *
      8  */
      9 
     10 #ifndef __LETABLEREFERENCE_H
     11 #define __LETABLEREFERENCE_H
     12 
     13 #include "LETypes.h"
     14 #include "LEFontInstance.h"
     15 
     16 
     17 #define kQuestionmarkTableTag  0x3F3F3F3FUL
     18 #define kTildeTableTag  0x7e7e7e7eUL
     19 #ifdef __cplusplus
     20 
     21 // internal - interface for range checking
     22 U_NAMESPACE_BEGIN
     23 
     24 #if LE_ASSERT_BAD_FONT
     25 class LETableReference; // fwd
     26 /**
     27  *  defined in OpenTypeUtilities.cpp
     28  * @internal
     29  */
     30 extern void _debug_LETableReference(const char *f, int l, const char *msg, const LETableReference *what, const void *ptr, size_t len);
     31 
     32 #define LE_DEBUG_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0);
     33 #define LE_DEBUG_TR3(x,y,z) _debug_LETableReference(__FILE__, __LINE__, x, this, (const void*)y, (size_t)z);
     34 #if 0
     35 #define LE_TRACE_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0);
     36 #else
     37 #define LE_TRACE_TR(x)
     38 #endif
     39 
     40 #else
     41 #define LE_DEBUG_TR(x)
     42 #define LE_DEBUG_TR3(x,y,z)
     43 #define LE_TRACE_TR(x)
     44 #endif
     45 
     46 /**
     47  * @internal
     48  */
     49 class LETableReference {
     50 public:
     51 /**
     52  * @internal
     53  * Construct from a specific tag
     54  */
     55   LETableReference(const LEFontInstance* font, LETag tableTag, LEErrorCode &success) :
     56     fFont(font), fTag(tableTag), fParent(NULL), fStart(NULL),fLength(LE_UINTPTR_MAX) {
     57       loadTable(success);
     58     LE_TRACE_TR("INFO: new table load")
     59   }
     60 
     61   LETableReference(const LETableReference &parent, LEErrorCode &success) : fFont(parent.fFont), fTag(parent.fTag), fParent(&parent), fStart(parent.fStart), fLength(parent.fLength) {
     62     if(LE_FAILURE(success)) {
     63       clear();
     64     }
     65     LE_TRACE_TR("INFO: new clone")
     66   }
     67 
     68    LETableReference(const le_uint8* data, size_t length = LE_UINTPTR_MAX) :
     69     fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(data), fLength(length) {
     70     LE_TRACE_TR("INFO: new raw")
     71   }
     72   LETableReference() :
     73     fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(NULL), fLength(0) {
     74     LE_TRACE_TR("INFO: new empty")
     75   }
     76 
     77   ~LETableReference() {
     78     fTag=kTildeTableTag;
     79     LE_TRACE_TR("INFO: new dtor")
     80   }
     81 
     82   /**
     83    * @internal
     84    * @param length  if LE_UINTPTR_MAX means "whole table"
     85    * subset
     86    */
     87   LETableReference(const LETableReference &parent, size_t offset, size_t length,
     88                    LEErrorCode &err) :
     89     fFont(parent.fFont), fTag(parent.fTag), fParent(&parent),
     90     fStart((parent.fStart)+offset), fLength(length) {
     91     if(LE_SUCCESS(err)) {
     92       if(isEmpty()) {
     93         //err = LE_MISSING_FONT_TABLE_ERROR;
     94         clear(); // it's just empty. Not an error.
     95       } else if(offset >= fParent->fLength) {
     96         LE_DEBUG_TR3("offset out of range: (%p) +%d", NULL, offset);
     97         err = LE_INDEX_OUT_OF_BOUNDS_ERROR;
     98         clear();
     99       } else {
    100         if(fLength == LE_UINTPTR_MAX &&
    101            fParent->fLength != LE_UINTPTR_MAX) {
    102           fLength = (fParent->fLength) - offset; // decrement length as base address is incremented
    103         }
    104         if(fLength != LE_UINTPTR_MAX) {  // if we have bounds:
    105           if(offset+fLength > fParent->fLength) {
    106             LE_DEBUG_TR3("offset+fLength out of range: (%p) +%d", NULL, offset+fLength);
    107             err = LE_INDEX_OUT_OF_BOUNDS_ERROR; // exceeded
    108             clear();
    109           }
    110         }
    111       }
    112     } else {
    113       clear();
    114     }
    115     LE_TRACE_TR("INFO: new subset")
    116   }
    117 
    118   const void* getAlias() const { return (const void*)fStart; }
    119   const void* getAliasRAW() const { LE_DEBUG_TR("getAliasRAW()"); return (const void*)fStart; }
    120   le_bool isEmpty() const { return fStart==NULL || fLength==0; }
    121   le_bool isValid() const { return !isEmpty(); }
    122   le_bool hasBounds() const { return fLength!=LE_UINTPTR_MAX; }
    123   void clear() { fLength=0; fStart=NULL; }
    124   size_t getLength() const { return fLength; }
    125   const LEFontInstance* getFont() const { return fFont; }
    126   LETag getTag() const { return fTag; }
    127   const LETableReference* getParent() const { return fParent; }
    128 
    129   void addOffset(size_t offset, LEErrorCode &success) {
    130     if(hasBounds()) {
    131       if(offset > fLength) {
    132         LE_DEBUG_TR("addOffset off end");
    133         success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
    134         return;
    135       } else {
    136         fLength -= offset;
    137       }
    138     }
    139     fStart += offset;
    140   }
    141 
    142   size_t ptrToOffset(const void *atPtr, LEErrorCode &success) const {
    143     if(atPtr==NULL) return 0;
    144     if(LE_FAILURE(success)) return LE_UINTPTR_MAX;
    145     if((atPtr < fStart) ||
    146        (hasBounds() && (atPtr > fStart+fLength))) {
    147       LE_DEBUG_TR3("ptrToOffset args out of range: %p", atPtr, 0);
    148       success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
    149       return LE_UINTPTR_MAX;
    150     }
    151     return ((const le_uint8*)atPtr)-fStart;
    152   }
    153 
    154   /**
    155    * Clamp down the length, for range checking.
    156    */
    157   size_t contractLength(size_t newLength) {
    158     if(fLength!=LE_UINTPTR_MAX&&newLength>0&&newLength<=fLength) {
    159       fLength = newLength;
    160     }
    161     return fLength;
    162   }
    163 
    164   /**
    165    * Throw an error if offset+length off end
    166    */
    167 public:
    168   size_t verifyLength(size_t offset, size_t length, LEErrorCode &success) {
    169     if(isValid()&&
    170        LE_SUCCESS(success) &&
    171        fLength!=LE_UINTPTR_MAX && length!=LE_UINTPTR_MAX && offset!=LE_UINTPTR_MAX &&
    172        (offset+length)>fLength) {
    173       LE_DEBUG_TR3("verifyLength failed (%p) %d",NULL, offset+length);
    174       success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
    175 #if LE_ASSERT_BAD_FONT
    176       fprintf(stderr, "offset=%lu, len=%lu, would be at %p, (%lu) off end. End at %p\n", offset,length, fStart+offset+length, (offset+length-fLength), (offset+length-fLength)+fStart);
    177 #endif
    178     }
    179     return fLength;
    180   }
    181 
    182   /**
    183    * Change parent link to another
    184    */
    185   LETableReference &reparent(const LETableReference &base) {
    186     fParent = &base;
    187     return *this;
    188   }
    189 
    190   /**
    191    * remove parent link. Factory functions should do this.
    192    */
    193   void orphan(void) {
    194     fParent=NULL;
    195   }
    196 
    197 protected:
    198   const LEFontInstance* fFont;
    199   LETag  fTag;
    200   const LETableReference *fParent;
    201   const le_uint8 *fStart; // keep as 8 bit internally, for pointer math
    202   size_t fLength;
    203 
    204   void loadTable(LEErrorCode &success) {
    205     if(LE_SUCCESS(success)) {
    206       fStart = (const le_uint8*)(fFont->getFontTable(fTag, fLength)); // note - a null table is not an error.
    207     }
    208   }
    209 
    210   void setRaw(const void *data, size_t length = LE_UINTPTR_MAX) {
    211     fFont = NULL;
    212     fTag = kQuestionmarkTableTag;
    213     fParent = NULL;
    214     fStart = (const le_uint8*)data;
    215     fLength = length;
    216   }
    217 };
    218 
    219 
    220 template<class T>
    221 class LETableVarSizer {
    222  public:
    223   inline static size_t getSize();
    224 };
    225 
    226 // base definition- could override for adjustments
    227 template<class T> inline
    228 size_t LETableVarSizer<T>::getSize() {
    229   return sizeof(T);
    230 }
    231 
    232 /**
    233  * \def LE_VAR_ARRAY
    234  * @param x Type (T)
    235  * @param y some member that is of length ANY_NUMBER
    236  * Call this after defining a class, for example:
    237  *   LE_VAR_ARRAY(FeatureListTable,featureRecordArray)
    238  * this is roughly equivalent to:
    239  *   template<> inline size_t LETableVarSizer<FeatureListTable>::getSize() { return sizeof(FeatureListTable) - (sizeof(le_uint16)*ANY_NUMBER); }
    240  * it's a specialization that informs the LETableReference subclasses to NOT include the variable array in the size.
    241  * dereferencing NULL is valid here because we never actually dereference it, just inside sizeof.
    242  */
    243 #define LE_VAR_ARRAY(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return sizeof(x) - (sizeof(((const x*)0)->y)); }
    244 /**
    245  * \def LE_CORRECT_SIZE
    246  * @param x type (T)
    247  * @param y fixed size for T
    248  */
    249 #define LE_CORRECT_SIZE(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return y; }
    250 
    251 /**
    252  * Open a new entry based on an existing table
    253  */
    254 
    255 /**
    256  * \def LE_UNBOUNDED_ARRAY
    257  * define an array with no *known* bound. Will trim to available size.
    258  * @internal
    259  */
    260 #define LE_UNBOUNDED_ARRAY LE_UINT32_MAX
    261 
    262 template<class T>
    263 class LEReferenceToArrayOf : public LETableReference {
    264 public:
    265   LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, size_t offset, le_uint32 count)
    266     : LETableReference(parent, offset, LE_UINTPTR_MAX, success), fCount(count) {
    267     LE_TRACE_TR("INFO: new RTAO by offset")
    268     if(LE_SUCCESS(success)) {
    269       if(count == LE_UNBOUNDED_ARRAY) { // not a known length
    270         count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
    271       }
    272       LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success);
    273     }
    274     if(LE_FAILURE(success)) {
    275       fCount=0;
    276       clear();
    277     }
    278   }
    279 
    280   LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, le_uint32 count)
    281     : LETableReference(parent, parent.ptrToOffset(array, success), LE_UINTPTR_MAX, success), fCount(count) {
    282 LE_TRACE_TR("INFO: new RTAO")
    283     if(LE_SUCCESS(success)) {
    284       if(count == LE_UNBOUNDED_ARRAY) { // not a known length
    285         count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
    286       }
    287       LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success);
    288     }
    289     if(LE_FAILURE(success)) clear();
    290   }
    291  LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, size_t offset, le_uint32 count)
    292    : LETableReference(parent, parent.ptrToOffset(array, success)+offset, LE_UINTPTR_MAX, success), fCount(count) {
    293 LE_TRACE_TR("INFO: new RTAO")
    294     if(LE_SUCCESS(success)) {
    295       if(count == LE_UNBOUNDED_ARRAY) { // not a known length
    296         count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
    297       }
    298       LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success);
    299     }
    300     if(LE_FAILURE(success)) clear();
    301   }
    302 
    303  LEReferenceToArrayOf() :LETableReference(), fCount(0) {}
    304 
    305   le_uint32 getCount() const { return fCount; }
    306 
    307   using LETableReference::getAlias;
    308 
    309   const T *getAlias(le_uint32 i, LEErrorCode &success) const {
    310     return ((const T*)(((const char*)getAlias())+getOffsetFor(i, success)));
    311   }
    312 
    313   const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }
    314 
    315   const T& getObject(le_uint32 i, LEErrorCode &success) const {
    316     return *getAlias(i,success);
    317   }
    318 
    319   const T& operator()(le_uint32 i, LEErrorCode &success) const {
    320     return *getAlias(i,success);
    321   }
    322 
    323   size_t getOffsetFor(le_uint32 i, LEErrorCode &success) const {
    324     if(LE_SUCCESS(success)&&i<getCount()) {
    325       return LETableVarSizer<T>::getSize()*i;
    326     } else {
    327       success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
    328     }
    329     return 0;
    330   }
    331 
    332   LEReferenceToArrayOf<T> &reparent(const LETableReference &base) {
    333     fParent = &base;
    334     return *this;
    335   }
    336 
    337  LEReferenceToArrayOf(const LETableReference& parent, LEErrorCode & success) : LETableReference(parent,0, LE_UINTPTR_MAX, success), fCount(0) {
    338     LE_TRACE_TR("INFO: null RTAO")
    339   }
    340 
    341 private:
    342   le_uint32 fCount;
    343 };
    344 
    345 
    346 template<class T>
    347 class LEReferenceTo : public LETableReference {
    348 public:
    349   /**
    350    * open a sub reference.
    351    * @param parent parent reference
    352    * @param success error status
    353    * @param atPtr location of reference - if NULL, will be at offset zero (i.e. downcast of parent). Otherwise must be a pointer within parent's bounds.
    354    */
    355  inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr)
    356     : LETableReference(parent, parent.ptrToOffset(atPtr, success), LE_UINTPTR_MAX, success) {
    357     verifyLength(0, LETableVarSizer<T>::getSize(), success);
    358     if(LE_FAILURE(success)) clear();
    359   }
    360   /**
    361    * ptr plus offset
    362    */
    363  inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr, size_t offset)
    364     : LETableReference(parent, parent.ptrToOffset(atPtr, success)+offset, LE_UINTPTR_MAX, success) {
    365     verifyLength(0, LETableVarSizer<T>::getSize(), success);
    366     if(LE_FAILURE(success)) clear();
    367   }
    368  inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, size_t offset)
    369     : LETableReference(parent, offset, LE_UINTPTR_MAX, success) {
    370     verifyLength(0, LETableVarSizer<T>::getSize(), success);
    371     if(LE_FAILURE(success)) clear();
    372   }
    373  inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success)
    374     : LETableReference(parent, 0, LE_UINTPTR_MAX, success) {
    375     verifyLength(0, LETableVarSizer<T>::getSize(), success);
    376     if(LE_FAILURE(success)) clear();
    377   }
    378  inline LEReferenceTo(const LEFontInstance *font, LETag tableTag, LEErrorCode &success)
    379    : LETableReference(font, tableTag, success) {
    380     verifyLength(0, LETableVarSizer<T>::getSize(), success);
    381     if(LE_FAILURE(success)) clear();
    382   }
    383  inline LEReferenceTo(const le_uint8 *data, size_t length = LE_UINTPTR_MAX) : LETableReference(data, length) {}
    384  inline LEReferenceTo(const T *data, size_t length = LE_UINTPTR_MAX) : LETableReference((const le_uint8*)data, length) {}
    385  inline LEReferenceTo() : LETableReference(NULL) {}
    386 
    387  inline LEReferenceTo<T>& operator=(const T* other) {
    388     setRaw(other);
    389     return *this;
    390   }
    391 
    392   LEReferenceTo<T> &reparent(const LETableReference &base) {
    393     fParent = &base;
    394     return *this;
    395   }
    396 
    397   /**
    398    * roll forward by one <T> size.
    399    * same as addOffset(LETableVarSizer<T>::getSize(),success)
    400    */
    401   void addObject(LEErrorCode &success) {
    402     addOffset(LETableVarSizer<T>::getSize(), success);
    403   }
    404   void addObject(size_t count, LEErrorCode &success) {
    405     addOffset(LETableVarSizer<T>::getSize()*count, success);
    406   }
    407 
    408   const T *operator->() const { return getAlias(); }
    409   const T *getAlias() const { return (const T*)fStart; }
    410   const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }
    411 };
    412 
    413 
    414 U_NAMESPACE_END
    415 
    416 #endif
    417 
    418 #endif
    419