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