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