| // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef OTS_H_ | 
 | #define OTS_H_ | 
 |  | 
 | #include <stddef.h> | 
 | #include <cstdarg> | 
 | #include <cstddef> | 
 | #include <cstdio> | 
 | #include <cstdlib> | 
 | #include <cstring> | 
 | #include <limits> | 
 |  | 
 | #include "opentype-sanitiser.h" | 
 |  | 
 | // arraysize borrowed from base/basictypes.h | 
 | template <typename T, size_t N> | 
 | char (&ArraySizeHelper(T (&array)[N]))[N]; | 
 | #define arraysize(array) (sizeof(ArraySizeHelper(array))) | 
 |  | 
 | namespace ots { | 
 |  | 
 | #if !defined(OTS_DEBUG) | 
 | #define OTS_FAILURE() false | 
 | #else | 
 | #define OTS_FAILURE() \ | 
 |   (\ | 
 |     std::fprintf(stderr, "ERROR at %s:%d (%s)\n", \ | 
 |                  __FILE__, __LINE__, __FUNCTION__) \ | 
 |     && false\ | 
 |   ) | 
 | #endif | 
 |  | 
 | // All OTS_FAILURE_* macros ultimately evaluate to 'false', just like the original | 
 | // message-less OTS_FAILURE(), so that the current parser will return 'false' as | 
 | // its result (indicating a failure). | 
 |  | 
 | #if !defined(OTS_DEBUG) | 
 | #define OTS_MESSAGE_(level,otf_,...) \ | 
 |   (otf_)->context->Message(level,__VA_ARGS__) | 
 | #else | 
 | #define OTS_MESSAGE_(level,otf_,...) \ | 
 |   OTS_FAILURE(), \ | 
 |   (otf_)->context->Message(level,__VA_ARGS__) | 
 | #endif | 
 |  | 
 | // Generate a simple message | 
 | #define OTS_FAILURE_MSG_(otf_,...) \ | 
 |   (OTS_MESSAGE_(0,otf_,__VA_ARGS__), false) | 
 |  | 
 | #define OTS_WARNING_MSG_(otf_,...) \ | 
 |   OTS_MESSAGE_(1,otf_,__VA_ARGS__) | 
 |  | 
 | // Generate a message with an associated table tag | 
 | #define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \ | 
 |   (OTS_MESSAGE_(0,otf_,"%4.4s: %s", tag_, msg_), false) | 
 |  | 
 | // Convenience macros for use in files that only handle a single table tag, | 
 | // defined as TABLE_NAME at the top of the file; the 'file' variable is | 
 | // expected to be the current OpenTypeFile pointer. | 
 | #define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__) | 
 |  | 
 | #define OTS_WARNING(...) OTS_WARNING_MSG_(file, TABLE_NAME ": " __VA_ARGS__) | 
 |  | 
 | // ----------------------------------------------------------------------------- | 
 | // Buffer helper class | 
 | // | 
 | // This class perform some trival buffer operations while checking for | 
 | // out-of-bounds errors. As a family they return false if anything is amiss, | 
 | // updating the current offset otherwise. | 
 | // ----------------------------------------------------------------------------- | 
 | class Buffer { | 
 |  public: | 
 |   Buffer(const uint8_t *buf, size_t len) | 
 |       : buffer_(buf), | 
 |         length_(len), | 
 |         offset_(0) { } | 
 |  | 
 |   bool Skip(size_t n_bytes) { | 
 |     return Read(NULL, n_bytes); | 
 |   } | 
 |  | 
 |   bool Read(uint8_t *buf, size_t n_bytes) { | 
 |     if (n_bytes > 1024 * 1024 * 1024) { | 
 |       return OTS_FAILURE(); | 
 |     } | 
 |     if ((offset_ + n_bytes > length_) || | 
 |         (offset_ > length_ - n_bytes)) { | 
 |       return OTS_FAILURE(); | 
 |     } | 
 |     if (buf) { | 
 |       std::memcpy(buf, buffer_ + offset_, n_bytes); | 
 |     } | 
 |     offset_ += n_bytes; | 
 |     return true; | 
 |   } | 
 |  | 
 |   inline bool ReadU8(uint8_t *value) { | 
 |     if (offset_ + 1 > length_) { | 
 |       return OTS_FAILURE(); | 
 |     } | 
 |     *value = buffer_[offset_]; | 
 |     ++offset_; | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool ReadU16(uint16_t *value) { | 
 |     if (offset_ + 2 > length_) { | 
 |       return OTS_FAILURE(); | 
 |     } | 
 |     std::memcpy(value, buffer_ + offset_, sizeof(uint16_t)); | 
 |     *value = ntohs(*value); | 
 |     offset_ += 2; | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool ReadS16(int16_t *value) { | 
 |     return ReadU16(reinterpret_cast<uint16_t*>(value)); | 
 |   } | 
 |  | 
 |   bool ReadU24(uint32_t *value) { | 
 |     if (offset_ + 3 > length_) { | 
 |       return OTS_FAILURE(); | 
 |     } | 
 |     *value = static_cast<uint32_t>(buffer_[offset_]) << 16 | | 
 |         static_cast<uint32_t>(buffer_[offset_ + 1]) << 8 | | 
 |         static_cast<uint32_t>(buffer_[offset_ + 2]); | 
 |     offset_ += 3; | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool ReadU32(uint32_t *value) { | 
 |     if (offset_ + 4 > length_) { | 
 |       return OTS_FAILURE(); | 
 |     } | 
 |     std::memcpy(value, buffer_ + offset_, sizeof(uint32_t)); | 
 |     *value = ntohl(*value); | 
 |     offset_ += 4; | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool ReadS32(int32_t *value) { | 
 |     return ReadU32(reinterpret_cast<uint32_t*>(value)); | 
 |   } | 
 |  | 
 |   bool ReadTag(uint32_t *value) { | 
 |     if (offset_ + 4 > length_) { | 
 |       return OTS_FAILURE(); | 
 |     } | 
 |     std::memcpy(value, buffer_ + offset_, sizeof(uint32_t)); | 
 |     offset_ += 4; | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool ReadR64(uint64_t *value) { | 
 |     if (offset_ + 8 > length_) { | 
 |       return OTS_FAILURE(); | 
 |     } | 
 |     std::memcpy(value, buffer_ + offset_, sizeof(uint64_t)); | 
 |     offset_ += 8; | 
 |     return true; | 
 |   } | 
 |  | 
 |   const uint8_t *buffer() const { return buffer_; } | 
 |   size_t offset() const { return offset_; } | 
 |   size_t length() const { return length_; } | 
 |  | 
 |   void set_offset(size_t newoffset) { offset_ = newoffset; } | 
 |  | 
 |  private: | 
 |   const uint8_t * const buffer_; | 
 |   const size_t length_; | 
 |   size_t offset_; | 
 | }; | 
 |  | 
 | // Round a value up to the nearest multiple of 4. Don't round the value in the | 
 | // case that rounding up overflows. | 
 | template<typename T> T Round4(T value) { | 
 |   if (std::numeric_limits<T>::max() - value < 3) { | 
 |     return value; | 
 |   } | 
 |   return (value + 3) & ~3; | 
 | } | 
 |  | 
 | template<typename T> T Round2(T value) { | 
 |   if (value == std::numeric_limits<T>::max()) { | 
 |     return value; | 
 |   } | 
 |   return (value + 1) & ~1; | 
 | } | 
 |  | 
 | bool IsValidVersionTag(uint32_t tag); | 
 |  | 
 | #define FOR_EACH_TABLE_TYPE \ | 
 |   F(cff, CFF) \ | 
 |   F(cmap, CMAP) \ | 
 |   F(cvt, CVT) \ | 
 |   F(fpgm, FPGM) \ | 
 |   F(gasp, GASP) \ | 
 |   F(gdef, GDEF) \ | 
 |   F(glyf, GLYF) \ | 
 |   F(gpos, GPOS) \ | 
 |   F(gsub, GSUB) \ | 
 |   F(hdmx, HDMX) \ | 
 |   F(head, HEAD) \ | 
 |   F(hhea, HHEA) \ | 
 |   F(hmtx, HMTX) \ | 
 |   F(kern, KERN) \ | 
 |   F(loca, LOCA) \ | 
 |   F(ltsh, LTSH) \ | 
 |   F(math, MATH) \ | 
 |   F(maxp, MAXP) \ | 
 |   F(name, NAME) \ | 
 |   F(os2, OS2) \ | 
 |   F(post, POST) \ | 
 |   F(prep, PREP) \ | 
 |   F(vdmx, VDMX) \ | 
 |   F(vorg, VORG) \ | 
 |   F(vhea, VHEA) \ | 
 |   F(vmtx, VMTX) | 
 |  | 
 | #define F(name, capname) struct OpenType##capname; | 
 | FOR_EACH_TABLE_TYPE | 
 | #undef F | 
 |  | 
 | struct OpenTypeFile { | 
 |   OpenTypeFile() { | 
 | #define F(name, capname) name = NULL; | 
 |     FOR_EACH_TABLE_TYPE | 
 | #undef F | 
 |   } | 
 |  | 
 |   uint32_t version; | 
 |   uint16_t num_tables; | 
 |   uint16_t search_range; | 
 |   uint16_t entry_selector; | 
 |   uint16_t range_shift; | 
 |  | 
 |   OTSContext *context; | 
 |  | 
 | #define F(name, capname) OpenType##capname *name; | 
 | FOR_EACH_TABLE_TYPE | 
 | #undef F | 
 | }; | 
 |  | 
 | #define F(name, capname) \ | 
 | bool ots_##name##_parse(OpenTypeFile *f, const uint8_t *d, size_t l); \ | 
 | bool ots_##name##_should_serialise(OpenTypeFile *f); \ | 
 | bool ots_##name##_serialise(OTSStream *s, OpenTypeFile *f); \ | 
 | void ots_##name##_free(OpenTypeFile *f); | 
 | // TODO(yusukes): change these function names to follow Chromium coding rule. | 
 | FOR_EACH_TABLE_TYPE | 
 | #undef F | 
 |  | 
 | }  // namespace ots | 
 |  | 
 | #endif  // OTS_H_ |