1 /* 2 * -*- c++ -*- 3 * 4 * (C) Copyright IBM Corp. and others 2015 - 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 const T *ret = getAlias(i, success); 317 if (LE_FAILURE(success) || ret==NULL) { 318 return *(new T(0)); 319 } else { 320 return *ret; 321 } 322 } 323 324 const T& operator()(le_uint32 i, LEErrorCode &success) const { 325 return *getAlias(i,success); 326 } 327 328 size_t getOffsetFor(le_uint32 i, LEErrorCode &success) const { 329 if(LE_SUCCESS(success)&&i<getCount()) { 330 return LETableVarSizer<T>::getSize()*i; 331 } else { 332 success = LE_INDEX_OUT_OF_BOUNDS_ERROR; 333 } 334 return 0; 335 } 336 337 LEReferenceToArrayOf<T> &reparent(const LETableReference &base) { 338 fParent = &base; 339 return *this; 340 } 341 342 LEReferenceToArrayOf(const LETableReference& parent, LEErrorCode & success) : LETableReference(parent,0, LE_UINTPTR_MAX, success), fCount(0) { 343 LE_TRACE_TR("INFO: null RTAO") 344 } 345 346 private: 347 le_uint32 fCount; 348 }; 349 350 351 template<class T> 352 class LEReferenceTo : public LETableReference { 353 public: 354 /** 355 * open a sub reference. 356 * @param parent parent reference 357 * @param success error status 358 * @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. 359 */ 360 inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr) 361 : LETableReference(parent, parent.ptrToOffset(atPtr, success), LE_UINTPTR_MAX, success) { 362 verifyLength(0, LETableVarSizer<T>::getSize(), success); 363 if(LE_FAILURE(success)) clear(); 364 } 365 /** 366 * ptr plus offset 367 */ 368 inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr, size_t offset) 369 : LETableReference(parent, parent.ptrToOffset(atPtr, success)+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, size_t offset) 374 : LETableReference(parent, offset, LE_UINTPTR_MAX, success) { 375 verifyLength(0, LETableVarSizer<T>::getSize(), success); 376 if(LE_FAILURE(success)) clear(); 377 } 378 inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success) 379 : LETableReference(parent, 0, LE_UINTPTR_MAX, success) { 380 verifyLength(0, LETableVarSizer<T>::getSize(), success); 381 if(LE_FAILURE(success)) clear(); 382 } 383 inline LEReferenceTo(const LEFontInstance *font, LETag tableTag, LEErrorCode &success) 384 : LETableReference(font, tableTag, success) { 385 verifyLength(0, LETableVarSizer<T>::getSize(), success); 386 if(LE_FAILURE(success)) clear(); 387 } 388 inline LEReferenceTo(const le_uint8 *data, size_t length = LE_UINTPTR_MAX) : LETableReference(data, length) {} 389 inline LEReferenceTo(const T *data, size_t length = LE_UINTPTR_MAX) : LETableReference((const le_uint8*)data, length) {} 390 inline LEReferenceTo() : LETableReference(NULL) {} 391 392 inline LEReferenceTo<T>& operator=(const T* other) { 393 setRaw(other); 394 return *this; 395 } 396 397 LEReferenceTo<T> &reparent(const LETableReference &base) { 398 fParent = &base; 399 return *this; 400 } 401 402 /** 403 * roll forward by one <T> size. 404 * same as addOffset(LETableVarSizer<T>::getSize(),success) 405 */ 406 void addObject(LEErrorCode &success) { 407 addOffset(LETableVarSizer<T>::getSize(), success); 408 } 409 void addObject(size_t count, LEErrorCode &success) { 410 addOffset(LETableVarSizer<T>::getSize()*count, success); 411 } 412 413 const T *operator->() const { return getAlias(); } 414 const T *getAlias() const { return (const T*)fStart; } 415 const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; } 416 }; 417 418 419 U_NAMESPACE_END 420 421 #endif 422 423 #endif 424