123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- /*
- * -*- c++ -*-
- *
- * (C) Copyright IBM Corp. and others 2015 - All Rights Reserved
- *
- * Range checking
- *
- */
- #ifndef __LETABLEREFERENCE_H
- #define __LETABLEREFERENCE_H
- #include "LETypes.h"
- #include "LEFontInstance.h"
- #define kQuestionmarkTableTag 0x3F3F3F3FUL
- #define kTildeTableTag 0x7e7e7e7eUL
- #ifdef __cplusplus
- // internal - interface for range checking
- U_NAMESPACE_BEGIN
- #if LE_ASSERT_BAD_FONT
- class LETableReference; // fwd
- /**
- * defined in OpenTypeUtilities.cpp
- * @internal
- */
- extern void _debug_LETableReference(const char *f, int l, const char *msg, const LETableReference *what, const void *ptr, size_t len);
- #define LE_DEBUG_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0);
- #define LE_DEBUG_TR3(x,y,z) _debug_LETableReference(__FILE__, __LINE__, x, this, (const void*)y, (size_t)z);
- #if 0
- #define LE_TRACE_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0);
- #else
- #define LE_TRACE_TR(x)
- #endif
- #else
- #define LE_DEBUG_TR(x)
- #define LE_DEBUG_TR3(x,y,z)
- #define LE_TRACE_TR(x)
- #endif
- /**
- * @internal
- */
- class LETableReference {
- public:
- /**
- * @internal
- * Construct from a specific tag
- */
- LETableReference(const LEFontInstance* font, LETag tableTag, LEErrorCode &success) :
- fFont(font), fTag(tableTag), fParent(NULL), fStart(NULL),fLength(LE_UINTPTR_MAX) {
- loadTable(success);
- LE_TRACE_TR("INFO: new table load")
- }
- LETableReference(const LETableReference &parent, LEErrorCode &success) : fFont(parent.fFont), fTag(parent.fTag), fParent(&parent), fStart(parent.fStart), fLength(parent.fLength) {
- if(LE_FAILURE(success)) {
- clear();
- }
- LE_TRACE_TR("INFO: new clone")
- }
- LETableReference(const le_uint8* data, size_t length = LE_UINTPTR_MAX) :
- fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(data), fLength(length) {
- LE_TRACE_TR("INFO: new raw")
- }
- LETableReference() :
- fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(NULL), fLength(0) {
- LE_TRACE_TR("INFO: new empty")
- }
- ~LETableReference() {
- fTag=kTildeTableTag;
- LE_TRACE_TR("INFO: new dtor")
- }
- /**
- * @internal
- * @param length if LE_UINTPTR_MAX means "whole table"
- * subset
- */
- LETableReference(const LETableReference &parent, size_t offset, size_t length,
- LEErrorCode &err) :
- fFont(parent.fFont), fTag(parent.fTag), fParent(&parent),
- fStart((parent.fStart)+offset), fLength(length) {
- if(LE_SUCCESS(err)) {
- if(isEmpty()) {
- //err = LE_MISSING_FONT_TABLE_ERROR;
- clear(); // it's just empty. Not an error.
- } else if(offset >= fParent->fLength) {
- LE_DEBUG_TR3("offset out of range: (%p) +%d", NULL, offset);
- err = LE_INDEX_OUT_OF_BOUNDS_ERROR;
- clear();
- } else {
- if(fLength == LE_UINTPTR_MAX &&
- fParent->fLength != LE_UINTPTR_MAX) {
- fLength = (fParent->fLength) - offset; // decrement length as base address is incremented
- }
- if(fLength != LE_UINTPTR_MAX) { // if we have bounds:
- if(offset+fLength > fParent->fLength) {
- LE_DEBUG_TR3("offset+fLength out of range: (%p) +%d", NULL, offset+fLength);
- err = LE_INDEX_OUT_OF_BOUNDS_ERROR; // exceeded
- clear();
- }
- }
- }
- } else {
- clear();
- }
- LE_TRACE_TR("INFO: new subset")
- }
- const void* getAlias() const { return (const void*)fStart; }
- const void* getAliasRAW() const { LE_DEBUG_TR("getAliasRAW()"); return (const void*)fStart; }
- le_bool isEmpty() const { return fStart==NULL || fLength==0; }
- le_bool isValid() const { return !isEmpty(); }
- le_bool hasBounds() const { return fLength!=LE_UINTPTR_MAX; }
- void clear() { fLength=0; fStart=NULL; }
- size_t getLength() const { return fLength; }
- const LEFontInstance* getFont() const { return fFont; }
- LETag getTag() const { return fTag; }
- const LETableReference* getParent() const { return fParent; }
- void addOffset(size_t offset, LEErrorCode &success) {
- if(hasBounds()) {
- if(offset > fLength) {
- LE_DEBUG_TR("addOffset off end");
- success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
- return;
- } else {
- fLength -= offset;
- }
- }
- fStart += offset;
- }
- size_t ptrToOffset(const void *atPtr, LEErrorCode &success) const {
- if(atPtr==NULL) return 0;
- if(LE_FAILURE(success)) return LE_UINTPTR_MAX;
- if((atPtr < fStart) ||
- (hasBounds() && (atPtr > fStart+fLength))) {
- LE_DEBUG_TR3("ptrToOffset args out of range: %p", atPtr, 0);
- success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
- return LE_UINTPTR_MAX;
- }
- return ((const le_uint8*)atPtr)-fStart;
- }
- /**
- * Clamp down the length, for range checking.
- */
- size_t contractLength(size_t newLength) {
- if(fLength!=LE_UINTPTR_MAX&&newLength>0&&newLength<=fLength) {
- fLength = newLength;
- }
- return fLength;
- }
- /**
- * Throw an error if offset+length off end
- */
- public:
- size_t verifyLength(size_t offset, size_t length, LEErrorCode &success) {
- if(isValid()&&
- LE_SUCCESS(success) &&
- fLength!=LE_UINTPTR_MAX && length!=LE_UINTPTR_MAX && offset!=LE_UINTPTR_MAX &&
- (offset+length)>fLength) {
- LE_DEBUG_TR3("verifyLength failed (%p) %d",NULL, offset+length);
- success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
- #if LE_ASSERT_BAD_FONT
- 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);
- #endif
- }
- return fLength;
- }
- /**
- * Throw an error if size*count overflows
- */
- size_t verifyLength(size_t offset, size_t size, le_uint32 count, LEErrorCode &success) {
- if(count!=0 && size>LE_UINT32_MAX/count) {
- LE_DEBUG_TR3("verifyLength failed size=%u, count=%u", size, count);
- success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
- return 0;
- }
- return verifyLength(offset, size*count, success);
- }
- /**
- * Change parent link to another
- */
- LETableReference &reparent(const LETableReference &base) {
- fParent = &base;
- return *this;
- }
- /**
- * remove parent link. Factory functions should do this.
- */
- void orphan(void) {
- fParent=NULL;
- }
- protected:
- const LEFontInstance* fFont;
- LETag fTag;
- const LETableReference *fParent;
- const le_uint8 *fStart; // keep as 8 bit internally, for pointer math
- size_t fLength;
- void loadTable(LEErrorCode &success) {
- if(LE_SUCCESS(success)) {
- fStart = (const le_uint8*)(fFont->getFontTable(fTag, fLength)); // note - a null table is not an error.
- }
- }
- void setRaw(const void *data, size_t length = LE_UINTPTR_MAX) {
- fFont = NULL;
- fTag = kQuestionmarkTableTag;
- fParent = NULL;
- fStart = (const le_uint8*)data;
- fLength = length;
- }
- };
- template<class T>
- class LETableVarSizer {
- public:
- inline static size_t getSize();
- };
- // base definition- could override for adjustments
- template<class T> inline
- size_t LETableVarSizer<T>::getSize() {
- return sizeof(T);
- }
- /**
- * \def LE_VAR_ARRAY
- * @param x Type (T)
- * @param y some member that is of length ANY_NUMBER
- * Call this after defining a class, for example:
- * LE_VAR_ARRAY(FeatureListTable,featureRecordArray)
- * this is roughly equivalent to:
- * template<> inline size_t LETableVarSizer<FeatureListTable>::getSize() { return sizeof(FeatureListTable) - (sizeof(le_uint16)*ANY_NUMBER); }
- * it's a specialization that informs the LETableReference subclasses to NOT include the variable array in the size.
- * dereferencing NULL is valid here because we never actually dereference it, just inside sizeof.
- */
- #define LE_VAR_ARRAY(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return sizeof(x) - (sizeof(((const x*)0)->y)); }
- /**
- * \def LE_CORRECT_SIZE
- * @param x type (T)
- * @param y fixed size for T
- */
- #define LE_CORRECT_SIZE(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return y; }
- /**
- * Open a new entry based on an existing table
- */
- /**
- * \def LE_UNBOUNDED_ARRAY
- * define an array with no *known* bound. Will trim to available size.
- * @internal
- */
- #define LE_UNBOUNDED_ARRAY LE_UINT32_MAX
- template<class T>
- class LEReferenceToArrayOf : public LETableReference {
- public:
- LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, size_t offset, le_uint32 count)
- : LETableReference(parent, offset, LE_UINTPTR_MAX, success), fCount(count) {
- LE_TRACE_TR("INFO: new RTAO by offset")
- if(LE_SUCCESS(success)) {
- if(count == LE_UNBOUNDED_ARRAY) { // not a known length
- count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
- }
- LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
- }
- if(LE_FAILURE(success)) {
- fCount=0;
- clear();
- }
- }
- LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, le_uint32 count)
- : LETableReference(parent, parent.ptrToOffset(array, success), LE_UINTPTR_MAX, success), fCount(count) {
- LE_TRACE_TR("INFO: new RTAO")
- if(LE_SUCCESS(success)) {
- if(count == LE_UNBOUNDED_ARRAY) { // not a known length
- count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
- }
- LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
- }
- if(LE_FAILURE(success)) clear();
- }
- LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, size_t offset, le_uint32 count)
- : LETableReference(parent, parent.ptrToOffset(array, success)+offset, LE_UINTPTR_MAX, success), fCount(count) {
- LE_TRACE_TR("INFO: new RTAO")
- if(LE_SUCCESS(success)) {
- if(count == LE_UNBOUNDED_ARRAY) { // not a known length
- count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
- }
- LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
- }
- if(LE_FAILURE(success)) clear();
- }
- LEReferenceToArrayOf() :LETableReference(), fCount(0) {}
- le_uint32 getCount() const { return fCount; }
- using LETableReference::getAlias;
- const T *getAlias(le_uint32 i, LEErrorCode &success) const {
- return ((const T*)(((const char*)getAlias())+getOffsetFor(i, success)));
- }
- const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }
- const T& getObject(le_uint32 i, LEErrorCode &success) const {
- const T *ret = getAlias(i, success);
- if (LE_FAILURE(success) || ret==NULL) {
- return *(new T(0));
- } else {
- return *ret;
- }
- }
-
- const T& operator()(le_uint32 i, LEErrorCode &success) const {
- return *getAlias(i,success);
- }
- size_t getOffsetFor(le_uint32 i, LEErrorCode &success) const {
- if(LE_SUCCESS(success)&&i<getCount()) {
- return LETableVarSizer<T>::getSize()*i;
- } else {
- success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
- }
- return 0;
- }
- LEReferenceToArrayOf<T> &reparent(const LETableReference &base) {
- fParent = &base;
- return *this;
- }
- LEReferenceToArrayOf(const LETableReference& parent, LEErrorCode & success) : LETableReference(parent,0, LE_UINTPTR_MAX, success), fCount(0) {
- LE_TRACE_TR("INFO: null RTAO")
- }
- private:
- le_uint32 fCount;
- };
- template<class T>
- class LEReferenceTo : public LETableReference {
- public:
- /**
- * open a sub reference.
- * @param parent parent reference
- * @param success error status
- * @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.
- */
- inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr)
- : LETableReference(parent, parent.ptrToOffset(atPtr, success), LE_UINTPTR_MAX, success) {
- verifyLength(0, LETableVarSizer<T>::getSize(), success);
- if(LE_FAILURE(success)) clear();
- }
- /**
- * ptr plus offset
- */
- inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr, size_t offset)
- : LETableReference(parent, parent.ptrToOffset(atPtr, success)+offset, LE_UINTPTR_MAX, success) {
- verifyLength(0, LETableVarSizer<T>::getSize(), success);
- if(LE_FAILURE(success)) clear();
- }
- inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, size_t offset)
- : LETableReference(parent, offset, LE_UINTPTR_MAX, success) {
- verifyLength(0, LETableVarSizer<T>::getSize(), success);
- if(LE_FAILURE(success)) clear();
- }
- inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success)
- : LETableReference(parent, 0, LE_UINTPTR_MAX, success) {
- verifyLength(0, LETableVarSizer<T>::getSize(), success);
- if(LE_FAILURE(success)) clear();
- }
- inline LEReferenceTo(const LEFontInstance *font, LETag tableTag, LEErrorCode &success)
- : LETableReference(font, tableTag, success) {
- verifyLength(0, LETableVarSizer<T>::getSize(), success);
- if(LE_FAILURE(success)) clear();
- }
- inline LEReferenceTo(const le_uint8 *data, size_t length = LE_UINTPTR_MAX) : LETableReference(data, length) {}
- inline LEReferenceTo(const T *data, size_t length = LE_UINTPTR_MAX) : LETableReference((const le_uint8*)data, length) {}
- inline LEReferenceTo() : LETableReference(NULL) {}
- inline LEReferenceTo<T>& operator=(const T* other) {
- setRaw(other);
- return *this;
- }
- LEReferenceTo<T> &reparent(const LETableReference &base) {
- fParent = &base;
- return *this;
- }
- /**
- * roll forward by one <T> size.
- * same as addOffset(LETableVarSizer<T>::getSize(),success)
- */
- void addObject(LEErrorCode &success) {
- addOffset(LETableVarSizer<T>::getSize(), success);
- }
- void addObject(size_t count, LEErrorCode &success) {
- addOffset(LETableVarSizer<T>::getSize()*count, success);
- }
- const T *operator->() const { return getAlias(); }
- const T *getAlias() const { return (const T*)fStart; }
- const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }
- };
- U_NAMESPACE_END
- #endif
- #endif
|