diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/ots/src/ots.h | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/gfx/ots/src/ots.h b/gfx/ots/src/ots.h new file mode 100644 index 0000000000..434e068d48 --- /dev/null +++ b/gfx/ots/src/ots.h @@ -0,0 +1,364 @@ +// Copyright (c) 2009-2017 The OTS 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_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stddef.h> +#include <cstdarg> +#include <cstddef> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <limits> +#include <map> + +#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__) + +// 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 FontFile 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 = ots_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 = ots_ntohl(*value); + offset_ += 4; + return true; + } + + bool ReadS32(int32_t *value) { + return ReadU32(reinterpret_cast<uint32_t*>(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<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; +} + +// Check that a tag consists entirely of printable ASCII characters +bool CheckTag(uint32_t tag_value); + +#define OTS_TAG_CFF OTS_TAG('C','F','F',' ') +#define OTS_TAG_CFF2 OTS_TAG('C','F','F','2') +#define OTS_TAG_CMAP OTS_TAG('c','m','a','p') +#define OTS_TAG_COLR OTS_TAG('C','O','L','R') +#define OTS_TAG_CPAL OTS_TAG('C','P','A','L') +#define OTS_TAG_CVT OTS_TAG('c','v','t',' ') +#define OTS_TAG_FEAT OTS_TAG('F','e','a','t') +#define OTS_TAG_FPGM OTS_TAG('f','p','g','m') +#define OTS_TAG_GASP OTS_TAG('g','a','s','p') +#define OTS_TAG_GDEF OTS_TAG('G','D','E','F') +#define OTS_TAG_GLAT OTS_TAG('G','l','a','t') +#define OTS_TAG_GLOC OTS_TAG('G','l','o','c') +#define OTS_TAG_GLYF OTS_TAG('g','l','y','f') +#define OTS_TAG_GPOS OTS_TAG('G','P','O','S') +#define OTS_TAG_GSUB OTS_TAG('G','S','U','B') +#define OTS_TAG_HDMX OTS_TAG('h','d','m','x') +#define OTS_TAG_HEAD OTS_TAG('h','e','a','d') +#define OTS_TAG_HHEA OTS_TAG('h','h','e','a') +#define OTS_TAG_HMTX OTS_TAG('h','m','t','x') +#define OTS_TAG_KERN OTS_TAG('k','e','r','n') +#define OTS_TAG_LOCA OTS_TAG('l','o','c','a') +#define OTS_TAG_LTSH OTS_TAG('L','T','S','H') +#define OTS_TAG_MATH OTS_TAG('M','A','T','H') +#define OTS_TAG_MAXP OTS_TAG('m','a','x','p') +#define OTS_TAG_NAME OTS_TAG('n','a','m','e') +#define OTS_TAG_OS2 OTS_TAG('O','S','/','2') +#define OTS_TAG_POST OTS_TAG('p','o','s','t') +#define OTS_TAG_PREP OTS_TAG('p','r','e','p') +#define OTS_TAG_SILE OTS_TAG('S','i','l','e') +#define OTS_TAG_SILF OTS_TAG('S','i','l','f') +#define OTS_TAG_SILL OTS_TAG('S','i','l','l') +#define OTS_TAG_VDMX OTS_TAG('V','D','M','X') +#define OTS_TAG_VHEA OTS_TAG('v','h','e','a') +#define OTS_TAG_VMTX OTS_TAG('v','m','t','x') +#define OTS_TAG_VORG OTS_TAG('V','O','R','G') + +#define OTS_TAG_AVAR OTS_TAG('a','v','a','r') +#define OTS_TAG_CVAR OTS_TAG('c','v','a','r') +#define OTS_TAG_FVAR OTS_TAG('f','v','a','r') +#define OTS_TAG_GVAR OTS_TAG('g','v','a','r') +#define OTS_TAG_HVAR OTS_TAG('H','V','A','R') +#define OTS_TAG_MVAR OTS_TAG('M','V','A','R') +#define OTS_TAG_VVAR OTS_TAG('V','V','A','R') +#define OTS_TAG_STAT OTS_TAG('S','T','A','T') + +// See https://github.com/khaledhosny/ots/issues/219 +#define OTS_MAX_DECOMPRESSED_FILE_SIZE 300 * 1024 * 1024 +#define OTS_MAX_DECOMPRESSED_TABLE_SIZE 150 * 1024 * 1024 + +struct Font; +struct FontFile; +struct TableEntry; +struct Arena; + +class Table { + public: + explicit Table(Font *font, uint32_t tag, uint32_t type) + : m_tag(tag), + m_type(type), + m_font(font), + m_shouldSerialize(true) { + } + + virtual ~Table() { } + + virtual bool Parse(const uint8_t *data, size_t length) = 0; + virtual bool Serialize(OTSStream *out) = 0; + virtual bool ShouldSerialize(); + + // Return the tag (table type) this Table was parsed as, to support + // "poor man's RTTI" so that we know if we can safely down-cast to + // a specific Table subclass. The m_type field is initialized to the + // appropriate tag when a subclass is constructed, or to zero for + // TablePassthru (indicating unparsed data). + uint32_t Type() { return m_type; } + + // Return the tag assigned when this table was constructed. + uint32_t Tag() { return m_tag; } + + Font* GetFont() { return m_font; } + + bool Error(const char *format, ...); + bool Warning(const char *format, ...); + bool Drop(const char *format, ...); + bool DropGraphite(const char *format, ...); + bool DropVariations(const char *format, ...); + + private: + void Message(int level, const char *format, va_list va); + + uint32_t m_tag; + uint32_t m_type; + Font *m_font; + bool m_shouldSerialize; +}; + +class TablePassthru : public Table { + public: + explicit TablePassthru(Font *font, uint32_t tag) + : Table(font, tag, 0), + m_data(NULL), + m_length(0) { + } + + bool Parse(const uint8_t *data, size_t length); + bool Serialize(OTSStream *out); + + private: + const uint8_t *m_data; + size_t m_length; +}; + +struct Font { + explicit Font(FontFile *f) + : file(f), + version(0), + num_tables(0), + search_range(0), + entry_selector(0), + range_shift(0) { + } + + bool ParseTable(const TableEntry& tableinfo, const uint8_t* data, + Arena &arena); + Table* GetTable(uint32_t tag) const; + + // This checks that the returned Table is actually of the correct subclass + // for |tag|, so it can safely be downcast to the corresponding OpenTypeXXXX; + // if not (i.e. if the table was treated as Passthru), it will return NULL. + Table* GetTypedTable(uint32_t tag) const; + + // Insert a new table. Asserts if a table with the same tag already exists. + void AddTable(TableEntry entry, Table* table); + + // Drop all Graphite tables and don't parse new ones. + void DropGraphite(); + + // Drop all Variations tables and don't parse new ones. + void DropVariations(); + + FontFile *file; + + uint32_t version; + uint16_t num_tables; + uint16_t search_range; + uint16_t entry_selector; + uint16_t range_shift; + + private: + std::map<uint32_t, Table*> m_tables; +}; + +struct TableEntry { + uint32_t tag; + uint32_t offset; + uint32_t length; + uint32_t uncompressed_length; + uint32_t chksum; + + bool operator<(const TableEntry& other) const { + return tag < other.tag; + } +}; + +struct FontFile { + ~FontFile(); + + OTSContext *context; + std::map<TableEntry, Table*> tables; + std::map<uint32_t, TableEntry> table_entries; +}; + +} // namespace ots + +#endif // OTS_H_ |