1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * -*- c++ -*-
27  *
28  * (C) Copyright IBM Corp. and others 2013 - All Rights Reserved
29  *
30  * Range checking
31  *
32  */
33 
34 #ifndef __LETABLEREFERENCE_H
35 #define __LETABLEREFERENCE_H
36 
37 #include "LETypes.h"
38 #include "LEFontInstance.h"
39 
40 /**
41  * \def LE_ENABLE_RAW
42  * If this is 1, enables old non-safe raw access
43  */
44 #ifndef LE_ENABLE_RAW
45 #define LE_ENABLE_RAW 0
46 #endif
47 
48 #define kQuestionmarkTableTag  0x3F3F3F3FUL /* ???? */
49 #define kStaticTableTag  0x30303030UL  /* 0000 */
50 #define kTildeTableTag  0x7e7e7e7eUL /* ~~~~ */
51 #ifdef __cplusplus
52 
53 // internal - interface for range checking
54 U_NAMESPACE_BEGIN
55 
56 #if LE_ASSERT_BAD_FONT
57 
58 #ifndef LE_TRACE_TR
59 #define LE_TRACE_TR 0
60 #endif
61 
62 class LETableReference; // fwd
63 /**
64  *  defined in OpenTypeUtilities.cpp
65  * @internal
66  */
67 U_CAPI void U_EXPORT2 _debug_LETableReference(const char *f, int l, const char *msg, const LETableReference *what, const void *ptr, size_t len);
68 
69 #define LE_DEBUG_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0);
70 #define LE_DEBUG_TR3(x,y,z) _debug_LETableReference(__FILE__, __LINE__, x, this, (const void*)y, (size_t)z);
71 #if LE_TRACE_TR
72 #define _TRTRACE(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0);
73 #else
74 #define _TRTRACE(x)
75 #endif
76 
77 #else
78 #define LE_DEBUG_TR(x)
79 #define LE_DEBUG_TR3(x,y,z)
80 #define _TRTRACE(x)
81 #endif
82 
83 /**
84  * @internal
85  */
86 class LETableReference {
87 public:
88 
89   /**
90    * Dummy enum asserting that a value is actually static data
91    * and does not need to be range checked
92    */
93   enum EStaticData { kStaticData = 0 };
94 
95 /**
96  * @internal
97  * Construct from a specific tag
98  */
LETableReference(const LEFontInstance * font,LETag tableTag,LEErrorCode & success)99   LETableReference(const LEFontInstance* font, LETag tableTag, LEErrorCode &success) :
100     fFont(font), fTag(tableTag), fParent(NULL), fStart(NULL),fLength(LE_UINTPTR_MAX) {
101       loadTable(success);
102     _TRTRACE("INFO: new table load")
103   }
104 
LETableReference(const LETableReference & parent,LEErrorCode & success)105   LETableReference(const LETableReference &parent, LEErrorCode &success) : fFont(parent.fFont), fTag(parent.fTag), fParent(&parent), fStart(parent.fStart), fLength(parent.fLength) {
106     if(LE_FAILURE(success)) {
107       clear();
108     }
109     _TRTRACE("INFO: new clone")
110   }
111 
112 #if LE_ENABLE_RAW
113    /**
114     * Construct  without a parent LETR.
115     */
116    LETableReference(const le_uint8* data, size_t length = LE_UINTPTR_MAX) :
fFont(NULL)117     fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(data), fLength(length) {
118     _TRTRACE("INFO: new raw")
119   }
120 #endif
121 
122    /**
123     * Construct  without a parent LETR.
124     */
LETableReference(EStaticData,const le_uint8 * data,size_t length)125  LETableReference(EStaticData /* NOTUSED */, const le_uint8* data, size_t length) :
126     fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(data), fLength(length) {
127     _TRTRACE("INFO: new EStaticData")
128   }
129 
LETableReference()130   LETableReference() :
131     fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(NULL), fLength(0) {
132     _TRTRACE("INFO: new empty")
133   }
134 
~LETableReference()135   ~LETableReference() {
136     fTag= (LETag)kTildeTableTag;
137     _TRTRACE("INFO: new dtor")
138   }
139 
140   /**
141    * @internal
142    * @param length  if LE_UINTPTR_MAX means "whole table"
143    * subset
144    */
LETableReference(const LETableReference & parent,size_t offset,size_t length,LEErrorCode & err)145   LETableReference(const LETableReference &parent, size_t offset, size_t length,
146                    LEErrorCode &err) :
147     fFont(parent.fFont), fTag(parent.fTag), fParent(&parent),
148     fStart((parent.fStart)+offset), fLength(length) {
149     if(LE_SUCCESS(err)) {
150       if(isEmpty()) {
151         //err = LE_MISSING_FONT_TABLE_ERROR;
152         clear(); // it's just empty. Not an error.
153       } else if(offset >= fParent->fLength || (offset & 0x01)) {
154         LE_DEBUG_TR3("offset out of range or odd alignment: (%p) +%d", NULL, offset);
155         err = LE_INDEX_OUT_OF_BOUNDS_ERROR;
156         clear();
157       } else {
158         if(fLength == LE_UINTPTR_MAX &&
159            fParent->fLength != LE_UINTPTR_MAX) {
160           fLength = (fParent->fLength) - offset; // decrement length as base address is incremented
161         }
162         if(fLength != LE_UINTPTR_MAX) {  // if we have bounds:
163           if((offset+fLength < offset) || (offset+fLength > fParent->fLength)) {
164             LE_DEBUG_TR3("offset+fLength out of range: (%p) +%d", NULL, offset+fLength);
165             err = LE_INDEX_OUT_OF_BOUNDS_ERROR; // exceeded
166             clear();
167           }
168         }
169       }
170     } else {
171       clear();
172     }
173     _TRTRACE("INFO: new subset")
174   }
175 
getAlias()176   const void* getAlias() const { return (const void*)fStart; }
177 #ifndef LE_ENABLE_RAW
getAliasRAW()178   const void* getAliasRAW() const { LE_DEBUG_TR("getAliasRAW()"); return (const void*)fStart; }
179 #endif
isEmpty()180   le_bool isEmpty() const { return fStart==NULL || fLength==0; }
isValid()181   le_bool isValid() const { return !isEmpty(); }
hasBounds()182   le_bool hasBounds() const { return fLength!=LE_UINTPTR_MAX; }
clear()183   void clear() { fLength=0; fStart=NULL; }
getLength()184   size_t getLength() const { return fLength; }
getFont()185   const LEFontInstance* getFont() const { return fFont; }
getTag()186   LETag getTag() const { return fTag; }
getParent()187   const LETableReference* getParent() const { return fParent; }
188 
addOffset(size_t offset,LEErrorCode & success)189   void addOffset(size_t offset, LEErrorCode &success) {
190     if(hasBounds()) {
191       if(offset >= fLength) {
192         LE_DEBUG_TR("addOffset off end");
193         success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
194         return;
195       } else {
196         fLength -= offset;
197       }
198     }
199     fStart += offset;
200   }
201 
ptrToOffset(const void * atPtr,LEErrorCode & success)202   size_t ptrToOffset(const void *atPtr, LEErrorCode &success) const {
203     if(atPtr==NULL) return 0;
204     if(LE_FAILURE(success)) return LE_UINTPTR_MAX;
205     if((atPtr < fStart) ||
206        (hasBounds() && (atPtr >= fStart+fLength))) {
207       LE_DEBUG_TR3("ptrToOffset args out of range: %p", atPtr, 0);
208       success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
209       return LE_UINTPTR_MAX;
210     }
211     return ((const le_uint8*)atPtr)-fStart;
212   }
213 
214   /**
215    * Clamp down the length, for range checking.
216    */
contractLength(size_t newLength)217   size_t contractLength(size_t newLength) {
218     if(fLength!=LE_UINTPTR_MAX&&newLength>0&&newLength<=fLength) {
219       fLength = newLength;
220     }
221     return fLength;
222   }
223 
224   /**
225    * Throw an error if offset+length off end
226    */
227 public:
verifyLength(size_t offset,size_t length,LEErrorCode & success)228   size_t verifyLength(size_t offset, size_t length, LEErrorCode &success) {
229     if(isValid()&&
230        LE_SUCCESS(success) &&
231        fLength!=LE_UINTPTR_MAX && length!=LE_UINTPTR_MAX && offset!=LE_UINTPTR_MAX &&
232        (offset+length)>fLength) {
233       LE_DEBUG_TR3("verifyLength failed (%p) %d",NULL, offset+length);
234       success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
235 #if LE_ASSERT_BAD_FONT
236       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);
237 #endif
238     }
239     return fLength;
240   }
241 
242   /**
243   * Throw an error if size*count overflows
244   */
verifyLength(size_t offset,size_t size,le_uint32 count,LEErrorCode & success)245   size_t verifyLength(size_t offset, size_t size, le_uint32 count, LEErrorCode &success) {
246     if(count!=0 && size>LE_UINT32_MAX/count) {
247       LE_DEBUG_TR3("verifyLength failed size=%u, count=%u", size, count);
248       success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
249       return 0;
250     }
251     return verifyLength(offset, size*count, success);
252   }
253 
254   /**
255    * Change parent link to another
256    */
reparent(const LETableReference & base)257   LETableReference &reparent(const LETableReference &base) {
258     fParent = &base;
259     return *this;
260   }
261 
262   /**
263    * remove parent link. Factory functions should do this.
264    */
orphan(void)265   void orphan(void) {
266     fParent=NULL;
267   }
268 
269 protected:
270   const LEFontInstance* fFont;
271   LETag  fTag;
272   const LETableReference *fParent;
273   const le_uint8 *fStart; // keep as 8 bit internally, for pointer math
274   size_t fLength;
275 
loadTable(LEErrorCode & success)276   void loadTable(LEErrorCode &success) {
277     if(LE_SUCCESS(success)) {
278       fStart = (const le_uint8*)(fFont->getFontTable(fTag, fLength)); // note - a null table is not an error.
279     }
280   }
281 
282   void setRaw(const void *data, size_t length = LE_UINTPTR_MAX) {
283     fFont = NULL;
284     fTag = (LETag)kQuestionmarkTableTag;
285     fParent = NULL;
286     fStart = (const le_uint8*)data;
287     fLength = length;
288   }
289 
290   /**
291    * set this object pointing to static data
292    */
setTo(EStaticData,const void * data,size_t length)293   void setTo(EStaticData /*notused*/, const void *data, size_t length) {
294     fFont = NULL;
295     fTag = (LETag)kStaticTableTag;
296     fParent = NULL;
297     fStart = (const le_uint8*)data;
298     fLength = length;
299   }
300 };
301 
302 
303 template<class T>
304 class LETableVarSizer {
305  public:
306   inline static size_t getSize();
307 };
308 
309 // base definition- could override for adjustments
310 template<class T> inline
getSize()311 size_t LETableVarSizer<T>::getSize() {
312   return sizeof(T);
313 }
314 
315 /**
316  * \def LE_VAR_ARRAY
317  * @param x Type (T)
318  * @param y some member that is of length ANY_NUMBER
319  * Call this after defining a class, for example:
320  *   LE_VAR_ARRAY(FeatureListTable,featureRecordArray)
321  * this is roughly equivalent to:
322  *   template<> inline size_t LETableVarSizer<FeatureListTable>::getSize() { return sizeof(FeatureListTable) - (sizeof(le_uint16)*ANY_NUMBER); }
323  * it's a specialization that informs the LETableReference subclasses to NOT include the variable array in the size.
324  * dereferencing NULL is valid here because we never actually dereference it, just inside sizeof.
325  */
326 #define LE_VAR_ARRAY(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return sizeof(x) - (sizeof(((const x*)0)->y)); }
327 /**
328  * \def LE_CORRECT_SIZE
329  * @param x type (T)
330  * @param y fixed size for T
331  */
332 #define LE_CORRECT_SIZE(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return y; }
333 
334 /**
335  * Open a new entry based on an existing table
336  */
337 
338 template<class T>
339 class LEReferenceTo : public LETableReference {
340 public:
341   /**
342    * open a sub reference.
343    * @param parent parent reference
344    * @param success error status
345    * @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.
346    */
LEReferenceTo(const LETableReference & parent,LEErrorCode & success,const void * atPtr)347  inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr)
348     : LETableReference(parent, parent.ptrToOffset(atPtr, success), LE_UINTPTR_MAX, success) {
349     verifyLength(0, LETableVarSizer<T>::getSize(), success);
350     if(LE_FAILURE(success)) clear();
351   }
352   /**
353    * ptr plus offset
354    */
LEReferenceTo(const LETableReference & parent,LEErrorCode & success,const void * atPtr,size_t offset)355  inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr, size_t offset)
356     : LETableReference(parent, parent.ptrToOffset(atPtr, success)+offset, LE_UINTPTR_MAX, success) {
357     verifyLength(0, LETableVarSizer<T>::getSize(), success);
358     if(LE_FAILURE(success)) clear();
359   }
LEReferenceTo(const LETableReference & parent,LEErrorCode & success,size_t offset)360  inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success, size_t offset)
361     : LETableReference(parent, offset, LE_UINTPTR_MAX, success) {
362     verifyLength(0, LETableVarSizer<T>::getSize(), success);
363     if(LE_FAILURE(success)) clear();
364   }
LEReferenceTo(const LETableReference & parent,LEErrorCode & success)365  inline LEReferenceTo(const LETableReference &parent, LEErrorCode &success)
366     : LETableReference(parent, 0, LE_UINTPTR_MAX, success) {
367     verifyLength(0, LETableVarSizer<T>::getSize(), success);
368     if(LE_FAILURE(success)) clear();
369   }
LEReferenceTo(const LEFontInstance * font,LETag tableTag,LEErrorCode & success)370  inline LEReferenceTo(const LEFontInstance *font, LETag tableTag, LEErrorCode &success)
371    : LETableReference(font, tableTag, success) {
372     verifyLength(0, LETableVarSizer<T>::getSize(), success);
373     if(LE_FAILURE(success)) clear();
374   }
375 #if LE_ENABLE_RAW
LETableReference(data,length)376  inline LEReferenceTo(const le_uint8 *data, size_t length = LE_UINTPTR_MAX) : LETableReference(data, length) {}
377  inline LEReferenceTo(const T *data, size_t length = LE_UINTPTR_MAX) : LETableReference((const le_uint8*)data, length) {}
378 #endif
LEReferenceTo(EStaticData staticData,const le_uint8 * data,size_t length)379  inline LEReferenceTo(EStaticData staticData, const le_uint8 *data, size_t length) : LETableReference(staticData, data, length) {}
LEReferenceTo(EStaticData staticData,const T * data,size_t length)380  inline LEReferenceTo(EStaticData staticData, const T *data, size_t length) : LETableReference(staticData, (const le_uint8*)data, length) {}
381 
LEReferenceTo()382  inline LEReferenceTo() : LETableReference() {}
383 
384 #if LE_ENABLE_RAW
385  inline LEReferenceTo<T>& operator=(const T* other) {
386     setRaw(other);
387     return *this;
388   }
389 #endif
390 
setTo(LETableReference::EStaticData staticData,const T * other,size_t length)391  LEReferenceTo<T>& setTo(LETableReference::EStaticData staticData, const T* other, size_t length) {
392    LETableReference::setTo(staticData, other, length);
393    return *this;
394  }
395 
reparent(const LETableReference & base)396   LEReferenceTo<T> &reparent(const LETableReference &base) {
397     fParent = &base;
398     return *this;
399   }
400 
401   /**
402    * roll forward by one <T> size.
403    * same as addOffset(LETableVarSizer<T>::getSize(),success)
404    */
addObject(LEErrorCode & success)405   void addObject(LEErrorCode &success) {
406     addOffset(LETableVarSizer<T>::getSize(), success);
407   }
addObject(size_t count,LEErrorCode & success)408   void addObject(size_t count, LEErrorCode &success) {
409     addOffset(LETableVarSizer<T>::getSize()*count, success);
410   }
411 
412   const T *operator->() const { return getAlias(); }
413   const T *operator*() const { return getAlias(); }
getAlias()414   const T *getAlias() const { return (const T*)fStart; }
415 #if LE_ENABLE_RAW
getAliasRAW()416   const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }
417 #endif
418 
419 };
420 
421 
422 /**
423  * \def LE_UNBOUNDED_ARRAY
424  * define an array with no *known* bound. Will trim to available size.
425  * @internal
426  */
427 #define LE_UNBOUNDED_ARRAY LE_UINT32_MAX
428 
429 template<class T>
430 class LEReferenceToArrayOf : public LETableReference {
431 public:
LEReferenceToArrayOf(const LETableReference & parent,LEErrorCode & success,size_t offset,le_uint32 count)432   LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, size_t offset, le_uint32 count)
433     : LETableReference(parent, offset, LE_UINTPTR_MAX, success), fCount(count) {
434     _TRTRACE("INFO: new RTAO by offset")
435     if(LE_SUCCESS(success)) {
436       if(fCount == LE_UNBOUNDED_ARRAY) { // not a known length
437         fCount = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
438       }
439       LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
440     }
441     if(LE_FAILURE(success)) {
442       fCount=0;
443       clear();
444     }
445   }
446 
LEReferenceToArrayOf(const LETableReference & parent,LEErrorCode & success,const T * array,le_uint32 count)447   LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, le_uint32 count)
448     : LETableReference(parent, parent.ptrToOffset(array, success), LE_UINTPTR_MAX, success), fCount(count) {
449 _TRTRACE("INFO: new RTAO")
450     if(LE_SUCCESS(success)) {
451       if(fCount == LE_UNBOUNDED_ARRAY) { // not a known length
452         fCount = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
453       }
454       LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
455     }
456     if(LE_FAILURE(success)) clear();
457   }
LEReferenceToArrayOf(const LETableReference & parent,LEErrorCode & success,const T * array,size_t offset,le_uint32 count)458  LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, size_t offset, le_uint32 count)
459    : LETableReference(parent, parent.ptrToOffset(array, success)+offset, LE_UINTPTR_MAX, success), fCount(count) {
460 _TRTRACE("INFO: new RTAO")
461     if(LE_SUCCESS(success)) {
462       if(fCount == LE_UNBOUNDED_ARRAY) { // not a known length
463         fCount = getLength()/LETableVarSizer<T>::getSize(); // fit to max size
464       }
465       LETableReference::verifyLength(0, LETableVarSizer<T>::getSize(), fCount, success);
466     }
467     if(LE_FAILURE(success)) clear();
468   }
469 
LEReferenceToArrayOf()470  LEReferenceToArrayOf() :LETableReference(), fCount(0) {}
471 
getCount()472   le_uint32 getCount() const { return fCount; }
473 
getAlias()474   const T *getAlias() const { return (const T*)fStart; }
475 
getAlias(le_uint32 i,LEErrorCode & success)476   const T *getAlias(le_uint32 i, LEErrorCode &success) const {
477     return ((const T*)(((const char*)getAlias())+getOffsetFor(i, success)));
478   }
479 
480 #ifndef LE_ENABLE_RAW
getAliasRAW()481   const T *getAliasRAW() const { LE_DEBUG_TR("getAliasRAW<>"); return (const T*)fStart; }
482 #endif
483 
getObject(le_uint32 i,LEErrorCode & success)484   const T& getObject(le_uint32 i, LEErrorCode &success) const {
485       const T *ret = getAlias(i, success);
486       if (LE_FAILURE(success) || ret==NULL) {
487           return *(new T(0));
488       } else {
489           return *ret;
490      }
491   }
492 
493   /**
494    * by-value array accessor for integral types.
495    */
496   const T operator[](le_uint32 i) const {
497     LEErrorCode success = LE_NO_ERROR;
498     const T *ret = getAlias(i, success);
499     if(LE_FAILURE(success) || ret==NULL) {
500 #if LE_ASSERT_BAD_FONT
501       LE_DEBUG_TR3("Range error, out of bounds? (%p) #%d", NULL, i);
502 #endif
503       return T(0); // will not work for all types.
504     }
505     return *ret;
506   }
507 
getReference(le_uint32 i,LEErrorCode & success)508   const LEReferenceTo<T> getReference(le_uint32 i, LEErrorCode &success) const {
509     if(LE_FAILURE(success)) return LEReferenceTo<T>();
510     return LEReferenceTo<T>(*this, success, getAlias(i,success));
511   }
512 
operator()513   const T& operator()(le_uint32 i, LEErrorCode &success) const {
514     return *getAlias(i,success);
515   }
516 
getOffsetFor(le_uint32 i,LEErrorCode & success)517   size_t getOffsetFor(le_uint32 i, LEErrorCode &success) const {
518     if(LE_SUCCESS(success)&&i<getCount()) {
519       return LETableVarSizer<T>::getSize()*i;
520     } else {
521       LE_DEBUG_TR3("getOffsetFor failed (%p) index=%d",NULL, i);
522       success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
523     }
524     return 0;
525   }
526 
reparent(const LETableReference & base)527   LEReferenceToArrayOf<T> &reparent(const LETableReference &base) {
528     fParent = &base;
529     return *this;
530   }
531 
LEReferenceToArrayOf(const LETableReference & parent,LEErrorCode & success)532  LEReferenceToArrayOf(const LETableReference& parent, LEErrorCode & success) : LETableReference(parent,0, LE_UINTPTR_MAX, success), fCount(0) {
533     _TRTRACE("INFO: null RTAO")
534   }
535 
536 private:
537   le_uint32 fCount;
538 };
539 
540 
541 
542 
543 #ifdef _TRTRACE
544 #undef _TRTRACE
545 #endif
546 
547 U_NAMESPACE_END
548 
549 #endif
550 
551 #endif
552