4 * (C) Copyright IBM Corp. and others 2013 - 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 * Change parent link to another
185 LETableReference
&reparent(const LETableReference
&base
) {
191 * remove parent link. Factory functions should do this.
198 const LEFontInstance
* fFont
;
200 const LETableReference
*fParent
;
201 const le_uint8
*fStart
; // keep as 8 bit internally, for pointer math
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.
210 void setRaw(const void *data
, size_t length
= LE_UINTPTR_MAX
) {
212 fTag
= kQuestionmarkTableTag
;
214 fStart
= (const le_uint8
*)data
;
221 class LETableVarSizer
{
223 inline static size_t getSize();
226 // base definition- could override for adjustments
227 template<class T
> inline
228 size_t LETableVarSizer
<T
>::getSize() {
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.
243 #define LE_VAR_ARRAY(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return sizeof(x) - (sizeof(((const x*)0)->y)); }
245 * \def LE_CORRECT_SIZE
247 * @param y fixed size for T
249 #define LE_CORRECT_SIZE(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return y; }
252 * Open a new entry based on an existing table
256 * \def LE_UNBOUNDED_ARRAY
257 * define an array with no *known* bound. Will trim to available size.
260 #define LE_UNBOUNDED_ARRAY LE_UINT32_MAX
263 class LEReferenceToArrayOf
: public LETableReference
{
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
272 LETableReference::verifyLength(0, LETableVarSizer
<T
>::getSize()*count
, success
);
274 if(LE_FAILURE(success
)) {
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
287 LETableReference::verifyLength(0, LETableVarSizer
<T
>::getSize()*count
, success
);
289 if(LE_FAILURE(success
)) clear();
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
298 LETableReference::verifyLength(0, LETableVarSizer
<T
>::getSize()*count
, success
);
300 if(LE_FAILURE(success
)) clear();
303 LEReferenceToArrayOf() :LETableReference(), fCount(0) {}
305 le_uint32
getCount() const { return fCount
; }
307 using LETableReference::getAlias
;
309 const T
*getAlias(le_uint32 i
, LEErrorCode
&success
) const {
310 return ((const T
*)(((const char*)getAlias())+getOffsetFor(i
, success
)));
313 const T
*getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T
*)fStart
; }
315 const T
& getObject(le_uint32 i
, LEErrorCode
&success
) const {
316 return *getAlias(i
,success
);
319 const T
& operator()(le_uint32 i
, LEErrorCode
&success
) const {
320 return *getAlias(i
,success
);
323 size_t getOffsetFor(le_uint32 i
, LEErrorCode
&success
) const {
324 if(LE_SUCCESS(success
)&&i
<getCount()) {
325 return LETableVarSizer
<T
>::getSize()*i
;
327 success
= LE_INDEX_OUT_OF_BOUNDS_ERROR
;
332 LEReferenceToArrayOf
<T
> &reparent(const LETableReference
&base
) {
337 LEReferenceToArrayOf(const LETableReference
& parent
, LEErrorCode
& success
) : LETableReference(parent
,0, LE_UINTPTR_MAX
, success
), fCount(0) {
338 LE_TRACE_TR("INFO: null RTAO")
347 class LEReferenceTo
: public LETableReference
{
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.
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();
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();
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();
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();
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();
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
) {}
387 inline LEReferenceTo
<T
>& operator=(const T
* other
) {
392 LEReferenceTo
<T
> &reparent(const LETableReference
&base
) {
398 * roll forward by one <T> size.
399 * same as addOffset(LETableVarSizer<T>::getSize(),success)
401 void addObject(LEErrorCode
&success
) {
402 addOffset(LETableVarSizer
<T
>::getSize(), success
);
404 void addObject(size_t count
, LEErrorCode
&success
) {
405 addOffset(LETableVarSizer
<T
>::getSize()*count
, success
);
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
; }