2013-04-18 21:24:51 +00:00
/*
* - * - c + + - * -
*
* ( C ) Copyright IBM Corp . and others 2013 - 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 ;
}
/**
* 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 ( ) * count , 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 ( ) * count , 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 ( ) * count , 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 {
return * getAlias ( i , success ) ;
}
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 .
*/
2013-06-25 00:46:51 +00:00
inline LEReferenceTo ( const LETableReference & parent , LEErrorCode & success , const void * atPtr )
2013-04-18 21:24:51 +00:00
: LETableReference ( parent , parent . ptrToOffset ( atPtr , success ) , LE_UINTPTR_MAX , success ) {
verifyLength ( 0 , LETableVarSizer < T > : : getSize ( ) , success ) ;
if ( LE_FAILURE ( success ) ) clear ( ) ;
}
/**
* ptr plus offset
*/
2013-06-25 00:46:51 +00:00
inline LEReferenceTo ( const LETableReference & parent , LEErrorCode & success , const void * atPtr , size_t offset )
2013-04-18 21:24:51 +00:00
: LETableReference ( parent , parent . ptrToOffset ( atPtr , success ) + offset , LE_UINTPTR_MAX , success ) {
verifyLength ( 0 , LETableVarSizer < T > : : getSize ( ) , success ) ;
if ( LE_FAILURE ( success ) ) clear ( ) ;
}
2013-06-25 00:46:51 +00:00
inline LEReferenceTo ( const LETableReference & parent , LEErrorCode & success , size_t offset )
2013-04-18 21:24:51 +00:00
: LETableReference ( parent , offset , LE_UINTPTR_MAX , success ) {
verifyLength ( 0 , LETableVarSizer < T > : : getSize ( ) , success ) ;
if ( LE_FAILURE ( success ) ) clear ( ) ;
}
2013-06-25 00:46:51 +00:00
inline LEReferenceTo ( const LETableReference & parent , LEErrorCode & success )
2013-04-18 21:24:51 +00:00
: LETableReference ( parent , 0 , LE_UINTPTR_MAX , success ) {
verifyLength ( 0 , LETableVarSizer < T > : : getSize ( ) , success ) ;
if ( LE_FAILURE ( success ) ) clear ( ) ;
}
2013-06-25 00:46:51 +00:00
inline LEReferenceTo ( const LEFontInstance * font , LETag tableTag , LEErrorCode & success )
2013-04-18 21:24:51 +00:00
: LETableReference ( font , tableTag , success ) {
verifyLength ( 0 , LETableVarSizer < T > : : getSize ( ) , success ) ;
if ( LE_FAILURE ( success ) ) clear ( ) ;
}
2013-06-25 00:46:51 +00:00
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 ) { }
2013-04-18 21:24:51 +00:00
2013-06-25 00:46:51 +00:00
inline LEReferenceTo < T > & operator = ( const T * other ) {
2013-04-18 21:24:51 +00:00
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