4 * (C) Copyright IBM Corp. and others 2015 - All Rights Reserved
10 #ifndef __LETABLEREFERENCE_H
11 #define __LETABLEREFERENCE_H
14 #include "LEFontInstance.h"
17 #define kQuestionmarkTableTag 0x3F3F3F3FUL
18 #define kTildeTableTag 0x7e7e7e7eUL
21 // internal - interface for range checking
24 #if LE_ASSERT_BAD_FONT
25 class LETableReference; // fwd
27 * defined in OpenTypeUtilities.cpp
30 extern void _debug_LETableReference(const char *f, int l, const char *msg, const LETableReference *what, const void *ptr, size_t len);
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);
35 #define LE_TRACE_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0);
37 #define LE_TRACE_TR(x)
41 #define LE_DEBUG_TR(x)
42 #define LE_DEBUG_TR3(x,y,z)
43 #define LE_TRACE_TR(x)
49 class LETableReference {
53 * Construct from a specific tag
55 LETableReference(const LEFontInstance* font, LETag tableTag, LEErrorCode &success) :
56 fFont(font), fTag(tableTag), fParent(NULL), fStart(NULL),fLength(LE_UINTPTR_MAX) {
58 LE_TRACE_TR("INFO: new table load")
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)) {
65 LE_TRACE_TR("INFO: new clone")
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")
73 fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(NULL), fLength(0) {
74 LE_TRACE_TR("INFO: new empty")
79 LE_TRACE_TR("INFO: new dtor")
84 * @param length if LE_UINTPTR_MAX means "whole table"
87 LETableReference(const LETableReference &parent, size_t offset, size_t length,
89 fFont(parent.fFont), fTag(parent.fTag), fParent(&parent),
90 fStart((parent.fStart)+offset), fLength(length) {
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;
100 if(fLength == LE_UINTPTR_MAX &&
101 fParent->fLength != LE_UINTPTR_MAX) {
102 fLength = (fParent->fLength) - offset; // decrement length as base address is incremented
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
115 LE_TRACE_TR("INFO: new subset")
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; }
129 void addOffset(size_t offset, LEErrorCode &success) {
131 if(offset > fLength) {
132 LE_DEBUG_TR("addOffset off end");
133 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
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;
151 return ((const le_uint8*)atPtr)-fStart;
155 * Clamp down the length, for range checking.
157 size_t contractLength(size_t newLength) {
158 if(fLength!=LE_UINTPTR_MAX&&newLength>0&&newLength<=fLength) {
165 * Throw an error if offset+length off end
168 size_t verifyLength(size_t offset, size_t length, LEErrorCode &success) {
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);
183 * Throw an error if size*count overflows
185 size_t verifyLength(size_t offset, size_t size, le_uint32 count, LEErrorCode &success) {
186 if(count!=0 && size>LE_UINT32_MAX/count) {
187 LE_DEBUG_TR3("verifyLength failed size=%u, count=%u", size, count);
188 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
191 return verifyLength(offset, size*count, success);
195 * Change parent link to another
197 LETableReference &reparent(const LETableReference &base) {
203 * remove parent link. Factory functions should do this.
210 const LEFontInstance* fFont;
212 const LETableReference *fParent;
213 const le_uint8 *fStart; // keep as 8 bit internally, for pointer math
216 void loadTable(LEErrorCode &success) {
217 if(LE_SUCCESS(success)) {
218 fStart = (const le_uint8*)(fFont->getFontTable(fTag, fLength)); // note - a null table is not an error.
222 void setRaw(const void *data, size_t length = LE_UINTPTR_MAX) {
224 fTag = kQuestionmarkTableTag;
226 fStart = (const le_uint8*)data;
233 class LETableVarSizer {
235 inline static size_t getSize();
238 // base definition- could override for adjustments
239 template<class T> inline
240 size_t LETableVarSizer<T>::getSize() {
247 * @param y some member that is of length ANY_NUMBER
248 * Call this after defining a class, for example:
249 * LE_VAR_ARRAY(FeatureListTable,featureRecordArray)
250 * this is roughly equivalent to:
251 * template<> inline size_t LETableVarSizer<FeatureListTable>::getSize() { return sizeof(FeatureListTable) - (sizeof(le_uint16)*ANY_NUMBER); }
252 * it's a specialization that informs the LETableReference subclasses to NOT include the variable array in the size.
253 * dereferencing NULL is valid here because we never actually dereference it, just inside sizeof.
255 #define LE_VAR_ARRAY(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return sizeof(x) - (sizeof(((const x*)0)->y)); }
257 * \def LE_CORRECT_SIZE
259 * @param y fixed size for T
261 #define LE_CORRECT_SIZE(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return y; }
264 * Open a new entry based on an existing table
268 * \def LE_UNBOUNDED_ARRAY
269 * define an array with no *known* bound. Will trim to available size.
272 #define LE_UNBOUNDED_ARRAY LE_UINT32_MAX
275 class LEReferenceToArrayOf : public LETableReference {
277 LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, size_t offset, le_uint32 count)
278 : LETableReference(parent, offset, LE_UINTPTR_MAX, success), fCount(count) {
279 LE_TRACE_TR("INFO: new RTAO by offset")
280 if(LE_SUCCESS(success)) {
281 if(count == LE_UNBOUNDED_ARRAY) { // not a known length
282 count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
284 LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
286 if(LE_FAILURE(success)) {
292 LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, le_uint32 count)
293 : LETableReference(parent, parent.ptrToOffset(array, success), LE_UINTPTR_MAX, success), fCount(count) {
294 LE_TRACE_TR("INFO: new RTAO")
295 if(LE_SUCCESS(success)) {
296 if(count == LE_UNBOUNDED_ARRAY) { // not a known length
297 count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
299 LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
301 if(LE_FAILURE(success)) clear();
303 LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, size_t offset, le_uint32 count)
304 : LETableReference(parent, parent.ptrToOffset(array, success)+offset, LE_UINTPTR_MAX, success), fCount(count) {
305 LE_TRACE_TR("INFO: new RTAO")
306 if(LE_SUCCESS(success)) {
307 if(count == LE_UNBOUNDED_ARRAY) { // not a known length
308 count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
310 LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
312 if(LE_FAILURE(success)) clear();
315 LEReferenceToArrayOf() :LETableReference(), fCount(0) {}
317 le_uint32 getCount() const { return fCount; }
319 using LETableReference::getAlias;
321 const T *getAlias(le_uint32 i, LEErrorCode &success) const {
322 return ((const T*)(((const char*)getAlias())+getOffsetFor(i, success)));
325 const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }
327 const T& getObject(le_uint32 i, LEErrorCode &success) const {
328 const T *ret = getAlias(i, success);
329 if (LE_FAILURE(success) || ret==NULL) {
336 const T& operator()(le_uint32 i, LEErrorCode &success) const {
337 return *getAlias(i,success);
340 size_t getOffsetFor(le_uint32 i, LEErrorCode &success) const {
341 if(LE_SUCCESS(success)&&i<getCount()) {
342 return LETableVarSizer<T>::getSize()*i;
344 success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
349 LEReferenceToArrayOf<T> &reparent(const LETableReference &base) {
354 LEReferenceToArrayOf(const LETableReference& parent, LEErrorCode & success) : LETableReference(parent,0, LE_UINTPTR_MAX, success), fCount(0) {
355 LE_TRACE_TR("INFO: null RTAO")
364 class LEReferenceTo : public LETableReference {
367 * open a sub reference.
368 * @param parent parent reference
369 * @param success error status
370 * @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.
372 inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr)
373 : LETableReference(parent, parent.ptrToOffset(atPtr, success), LE_UINTPTR_MAX, success) {
374 verifyLength(0, LETableVarSizer<T>::getSize(), success);
375 if(LE_FAILURE(success)) clear();
380 inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr, size_t offset)
381 : LETableReference(parent, parent.ptrToOffset(atPtr, success)+offset, LE_UINTPTR_MAX, success) {
382 verifyLength(0, LETableVarSizer<T>::getSize(), success);
383 if(LE_FAILURE(success)) clear();
385 inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, size_t offset)
386 : LETableReference(parent, offset, LE_UINTPTR_MAX, success) {
387 verifyLength(0, LETableVarSizer<T>::getSize(), success);
388 if(LE_FAILURE(success)) clear();
390 inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success)
391 : LETableReference(parent, 0, LE_UINTPTR_MAX, success) {
392 verifyLength(0, LETableVarSizer<T>::getSize(), success);
393 if(LE_FAILURE(success)) clear();
395 inline LEReferenceTo(const LEFontInstance *font, LETag tableTag, LEErrorCode &success)
396 : LETableReference(font, tableTag, success) {
397 verifyLength(0, LETableVarSizer<T>::getSize(), success);
398 if(LE_FAILURE(success)) clear();
400 inline LEReferenceTo(const le_uint8 *data, size_t length = LE_UINTPTR_MAX) : LETableReference(data, length) {}
401 inline LEReferenceTo(const T *data, size_t length = LE_UINTPTR_MAX) : LETableReference((const le_uint8*)data, length) {}
402 inline LEReferenceTo() : LETableReference(NULL) {}
404 inline LEReferenceTo<T>& operator=(const T* other) {
409 LEReferenceTo<T> &reparent(const LETableReference &base) {
415 * roll forward by one <T> size.
416 * same as addOffset(LETableVarSizer<T>::getSize(),success)
418 void addObject(LEErrorCode &success) {
419 addOffset(LETableVarSizer<T>::getSize(), success);
421 void addObject(size_t count, LEErrorCode &success) {
422 addOffset(LETableVarSizer<T>::getSize()*count, success);
425 const T *operator->() const { return getAlias(); }
426 const T *getAlias() const { return (const T*)fStart; }
427 const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }