blob: 2d13f8d6d25423a921c0ce482d8eb2639103385e [file] [log] [blame]
// 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 <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__)
// 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<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 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;
}
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<uint32_t, std::pair<Font*, OutputTable> > TableMap;
struct OpenTypeFile {
OTSContext *context;
TableMap tables;
};
} // namespace ots
#undef FOR_EACH_TABLE_TYPE
#endif // OTS_H_