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