// 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 #include #include #include #include #include #include #include #include "opentype-sanitiser.h" // arraysize borrowed from base/basictypes.h template 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_,"%c%c%c%c: %s", OTS_UNTAG(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_(font->file, TABLE_NAME ": " __VA_ARGS__) #define OTS_WARNING(...) OTS_WARNING_MSG_(font->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(value)); } bool ReadU24(uint32_t *value) { if (offset_ + 3 > length_) { return OTS_FAILURE(); } *value = static_cast(buffer_[offset_]) << 16 | static_cast(buffer_[offset_ + 1]) << 8 | static_cast(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(value)); } 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_; } size_t remaining() const { return length_ - offset_; } 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 T Round4(T value) { if (std::numeric_limits::max() - value < 3) { return value; } return (value + 3) & ~3; } template T Round2(T value) { if (value == std::numeric_limits::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 Font; struct OpenTypeFile; #define F(name, capname) \ bool ots_##name##_parse(Font *f, const uint8_t *d, size_t l); \ bool ots_##name##_should_serialise(Font *f); \ bool ots_##name##_serialise(OTSStream *s, Font *f); \ void ots_##name##_reuse(Font *f, Font *o);\ void ots_##name##_free(Font *f); FOR_EACH_TABLE_TYPE #undef F struct Font { explicit Font(const OpenTypeFile *f) : file(f), version(0), num_tables(0), search_range(0), entry_selector(0), range_shift(0) { #define F(name, capname) \ name = NULL; \ name##_reused = false; FOR_EACH_TABLE_TYPE #undef F } ~Font() { #define F(name, capname) \ if (!name##_reused) {\ ots_##name##_free(this); \ } FOR_EACH_TABLE_TYPE #undef F } const OpenTypeFile *file; uint32_t version; uint16_t num_tables; uint16_t search_range; uint16_t entry_selector; uint16_t range_shift; #define F(name, capname) \ OpenType##capname *name; \ bool name##_reused; FOR_EACH_TABLE_TYPE #undef F }; struct OutputTable { uint32_t tag; size_t offset; size_t length; uint32_t chksum; bool operator<(const OutputTable& other) const { return tag < other.tag; } }; typedef std::map > TableMap; struct OpenTypeFile { OTSContext *context; TableMap tables; }; } // namespace ots #undef FOR_EACH_TABLE_TYPE #endif // OTS_H_