• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
LETableReference(const LEFontInstance * font,LETag tableTag,LEErrorCode & success)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 
LETableReference(const LETableReference & parent,LEErrorCode & success)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) :
fFont(NULL)69     fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(data), fLength(length) {
70     LE_TRACE_TR("INFO: new raw")
71   }
LETableReference()72   LETableReference() :
73     fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(NULL), fLength(0) {
74     LE_TRACE_TR("INFO: new empty")
75   }
76 
~LETableReference()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    */
LETableReference(const LETableReference & parent,size_t offset,size_t length,LEErrorCode & err)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 
getAlias()118   const void* getAlias() const { return (const void*)fStart; }
getAliasRAW()119   const void* getAliasRAW() const { LE_DEBUG_TR("getAliasRAW()"); return (const void*)fStart; }
isEmpty()120   le_bool isEmpty() const { return fStart==NULL || fLength==0; }
isValid()121   le_bool isValid() const { return !isEmpty(); }
hasBounds()122   le_bool hasBounds() const { return fLength!=LE_UINTPTR_MAX; }
clear()123   void clear() { fLength=0; fStart=NULL; }
getLength()124   size_t getLength() const { return fLength; }
getFont()125   const LEFontInstance* getFont() const { return fFont; }
getTag()126   LETag getTag() const { return fTag; }
getParent()127   const LETableReference* getParent() const { return fParent; }
128 
addOffset(size_t offset,LEErrorCode & success)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 
ptrToOffset(const void * atPtr,LEErrorCode & success)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    */
contractLength(size_t newLength)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:
verifyLength(size_t offset,size_t length,LEErrorCode & success)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    */
reparent(const LETableReference & base)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    */
orphan(void)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 
loadTable(LEErrorCode & success)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
getSize()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:
LEReferenceToArrayOf(const LETableReference & parent,LEErrorCode & success,size_t offset,le_uint32 count)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 
LEReferenceToArrayOf(const LETableReference & parent,LEErrorCode & success,const T * array,le_uint32 count)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   }
LEReferenceToArrayOf(const LETableReference & parent,LEErrorCode & success,const T * array,size_t offset,le_uint32 count)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 
LEReferenceToArrayOf()303  LEReferenceToArrayOf() :LETableReference(), fCount(0) {}
304 
getCount()305   le_uint32 getCount() const { return fCount; }
306 
307   using LETableReference::getAlias;
308 
getAlias(le_uint32 i,LEErrorCode & success)309   const T *getAlias(le_uint32 i, LEErrorCode &success) const {
310     return ((const T*)(((const char*)getAlias())+getOffsetFor(i, success)));
311   }
312 
getAliasRAW()313   const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }
314 
getObject(le_uint32 i,LEErrorCode & success)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 
operator()324   const T& operator()(le_uint32 i, LEErrorCode &success) const {
325     return *getAlias(i,success);
326   }
327 
getOffsetFor(le_uint32 i,LEErrorCode & success)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 
reparent(const LETableReference & base)337   LEReferenceToArrayOf<T> &reparent(const LETableReference &base) {
338     fParent = &base;
339     return *this;
340   }
341 
LEReferenceToArrayOf(const LETableReference & parent,LEErrorCode & success)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    */
LEReferenceTo(const LETableReference & parent,LEErrorCode & success,const void * atPtr)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    */
LEReferenceTo(const LETableReference & parent,LEErrorCode & success,const void * atPtr,size_t offset)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   }
LEReferenceTo(const LETableReference & parent,LEErrorCode & success,size_t offset)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   }
LEReferenceTo(const LETableReference & parent,LEErrorCode & success)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   }
LEReferenceTo(const LEFontInstance * font,LETag tableTag,LEErrorCode & success)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   }
LETableReference(data,length)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) {}
LEReferenceTo()390  inline LEReferenceTo() : LETableReference(NULL) {}
391 
392  inline LEReferenceTo<T>& operator=(const T* other) {
393     setRaw(other);
394     return *this;
395   }
396 
reparent(const LETableReference & base)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    */
addObject(LEErrorCode & success)406   void addObject(LEErrorCode &success) {
407     addOffset(LETableVarSizer<T>::getSize(), success);
408   }
addObject(size_t count,LEErrorCode & success)409   void addObject(size_t count, LEErrorCode &success) {
410     addOffset(LETableVarSizer<T>::getSize()*count, success);
411   }
412 
413   const T *operator->() const { return getAlias(); }
getAlias()414   const T *getAlias() const { return (const T*)fStart; }
getAliasRAW()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