diff options
author | Karl Berry <karl@freefriends.org> | 2006-11-26 01:57:09 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-11-26 01:57:09 +0000 |
commit | 31ff7ecb412ee470d0464bb210a0e9adabed065a (patch) | |
tree | 3a6d93ad2c99327f924b7b916db51314d98572b0 /Build/source/utils/lcdf-typetools/libefont/otf.cc | |
parent | bc57bba3992e10b518e1578cef31afba9b226bfa (diff) |
update to lcdf-typetools 2.46
git-svn-id: svn://tug.org/texlive/trunk@2536 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/lcdf-typetools/libefont/otf.cc')
-rw-r--r-- | Build/source/utils/lcdf-typetools/libefont/otf.cc | 192 |
1 files changed, 180 insertions, 12 deletions
diff --git a/Build/source/utils/lcdf-typetools/libefont/otf.cc b/Build/source/utils/lcdf-typetools/libefont/otf.cc index 22987bee00b..6b23caf7c64 100644 --- a/Build/source/utils/lcdf-typetools/libefont/otf.cc +++ b/Build/source/utils/lcdf-typetools/libefont/otf.cc @@ -2,7 +2,7 @@ /* otf.{cc,hh} -- OpenType font basics * - * Copyright (c) 2002-2004 Eddie Kohler + * Copyright (c) 2002-2006 Eddie Kohler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -24,6 +24,7 @@ #include <string.h> #include <algorithm> #include <efont/otfdata.hh> // for ntohl() +#include <efont/otfname.hh> #ifndef static_assert #define static_assert(c) switch (c) case 0: case (c): @@ -41,7 +42,7 @@ Font::Font(const String &s, ErrorHandler *errh) : _str(s) { _str.align(4); - _error = parse_header(errh ? errh : ErrorHandler::silent_handler()); + _error = parse_header(errh ? errh : ErrorHandler::ignore_handler()); } int @@ -87,6 +88,38 @@ Font::parse_header(ErrorHandler *errh) return 0; } +bool +Font::check_checksums(ErrorHandler *errh) const +{ + if (error() < 0) + return false; + int nt = ntables(); + bool ok = true; + for (int i = 0; i < nt; i++) { + const uint8_t *entry = data() + HEADER_SIZE + TABLE_DIR_ENTRY_SIZE * i; + String tbl = _str.substring(ULONG_AT(entry + 8), ULONG_AT(entry + 12)); + uint32_t sum = checksum(tbl); + if (ULONG_AT(entry) == 0x68656164 // 'head' + && tbl.length() >= 12) + sum -= ULONG_AT(tbl.data() + 8); + if (sum != ULONG_AT(entry + 4)) { + if (errh) + errh->error("table '%s' checksum error: %x vs. %x", Tag(ULONG_AT(entry)).text().c_str(), sum, ULONG_AT(entry + 4)); + ok = false; + } + } + return ok; +} + +int +Font::ntables() const +{ + if (error() < 0) + return 0; + else + return USHORT_AT(data() + 4); +} + String Font::table(Tag tag) const { @@ -99,13 +132,16 @@ Font::table(Tag tag) const return String(); } -int -Font::ntables() const +uint32_t +Font::table_checksum(Tag tag) const { if (error() < 0) - return 0; + return String(); + const uint8_t *entry = tag.table_entry(data() + HEADER_SIZE, USHORT_AT(data() + 4), TABLE_DIR_ENTRY_SIZE); + if (entry) + return ULONG_AT(entry + 4); else - return USHORT_AT(data() + 4); + return 0; } Tag @@ -117,6 +153,111 @@ Font::table_tag(int i) const return Tag(ULONG_AT(data() + HEADER_SIZE + TABLE_DIR_ENTRY_SIZE * i)); } +uint32_t +Font::checksum(const uint8_t *begin, const uint8_t *end) +{ + uint32_t sum = 0; + if (reinterpret_cast<uintptr_t>(begin) % 4) + for (; begin + 3 < end; begin += 4) + sum += (begin[0] << 24) + (begin[1] << 16) + (begin[2] << 8) + begin[3]; + else + for (; begin + 3 < end; begin += 4) + sum += ULONG_AT(begin); + uint32_t leftover = 0; + for (int i = 0; i < 4; i++) + leftover = (leftover << 8) + (begin < end ? *begin++ : 0); + return sum + leftover; +} + +uint32_t +Font::checksum(const String &s) +{ + return checksum(reinterpret_cast<const uint8_t *>(s.begin()), reinterpret_cast<const uint8_t *>(s.end())); +} + +namespace { +class TagCompar { public: + TagCompar(const Vector<Tag> &tags) : _tags(tags) { } + bool operator()(int a, int b) { return _tags[a] < _tags[b]; } + const Vector<Tag> &_tags; +}; +} + +Font +Font::make(bool truetype, const Vector<Tag>& tags, const Vector<String>& data) +{ + StringAccum sa; + + // create offset table + { + union { + uint8_t c[HEADER_SIZE]; + uint16_t s[HEADER_SIZE / 2]; + uint32_t l[HEADER_SIZE / 4]; + } hdr; + hdr.l[0] = (truetype ? htonl(0x00010000) : htonl(0x4F54544F)); + hdr.s[2] = htons(tags.size()); + int entrySelector; + for (entrySelector = 0; (2 << entrySelector) <= tags.size(); entrySelector++) + /* nada */; + hdr.s[3] = htons((1 << entrySelector) * 16); + hdr.s[4] = htons(entrySelector); + hdr.s[5] = htons((tags.size() - (1 << entrySelector)) * 16); + sa.append(&hdr.c[0], HEADER_SIZE); + } + + // sort tags + Vector<int> permut; + for (int i = 0; i < tags.size(); i++) + permut.push_back(i); + std::sort(permut.begin(), permut.end(), TagCompar(tags)); + + // table listing + uint32_t offset = HEADER_SIZE + TABLE_DIR_ENTRY_SIZE * tags.size(); + for (int *tp = permut.begin(); tp < permut.end(); tp++) { + union { + uint8_t c[TABLE_DIR_ENTRY_SIZE]; + uint32_t l[TABLE_DIR_ENTRY_SIZE / 4]; + } tdir; + tdir.l[0] = htonl(tags[*tp].value()); + + // discount current checksum adjustment in head table + uint32_t sum = checksum(data[*tp]); + if (tags[*tp] == Tag("head") && data[*tp].length() >= 12) { + const uint8_t *x = data[*tp].udata() + 8; + sum -= (x[0] << 24) + (x[1] << 16) + (x[2] << 8) + x[3]; + } + tdir.l[1] = htonl(sum); + + tdir.l[2] = htonl(offset); + tdir.l[3] = htonl(data[*tp].length()); + sa.append(&tdir.c[0], TABLE_DIR_ENTRY_SIZE); + offset += (data[*tp].length() + 3) & ~3; + } + + // actual tables + for (int *tp = permut.begin(); tp < permut.end(); tp++) { + sa << data[*tp]; + while (sa.length() % 4) + sa << '\0'; + } + + // fix 'head' table + for (int i = 0; i < tags.size(); i++) { + char *thdr = sa.data() + HEADER_SIZE + TABLE_DIR_ENTRY_SIZE * i; + if (ULONG_AT(thdr) == 0x68656164 && ULONG_AT(thdr + 12) >= 12) { + uint32_t offset = ULONG_AT(thdr + 8); + char *head = sa.data() + offset; + memset(head + 8, '\0', 4); + uint32_t allsum = checksum(reinterpret_cast<uint8_t *>(sa.data()), reinterpret_cast<uint8_t *>(sa.data() + sa.length())); + uint32_t *adj = reinterpret_cast<uint32_t *>(head + 8); + *adj = htonl(0xB1B0AFBA - allsum); + } + } + + return Font(sa.take_string()); +} + /************************** * Tag * @@ -223,7 +364,7 @@ ScriptList::assign(const String &str, ErrorHandler *errh) { _str = str; _str.align(4); - int result = check_header(errh ? errh : ErrorHandler::silent_handler()); + int result = check_header(errh ? errh : ErrorHandler::ignore_handler()); if (result < 0) _str = String(); return result; @@ -368,7 +509,7 @@ FeatureList::assign(const String &str, ErrorHandler *errh) { _str = str; _str.align(2); - int result = check_header(errh ? errh : ErrorHandler::silent_handler()); + int result = check_header(errh ? errh : ErrorHandler::ignore_handler()); if (result < 0) _str = String(); return result; @@ -404,7 +545,7 @@ FeatureList::params(int fid, int length, ErrorHandler *errh, bool old_style_offs if (_str.length() == 0 || length < 0) return String(); if (errh == 0) - errh = ErrorHandler::silent_handler(); + errh = ErrorHandler::ignore_handler(); const uint8_t *data = _str.udata(); int len = _str.length(); @@ -425,6 +566,33 @@ FeatureList::params(int fid, int length, ErrorHandler *errh, bool old_style_offs return _str.substring(poff, length); } +String +FeatureList::size_params(int fid, const Name &name, ErrorHandler *errh) const +{ + // implement 'size' checks from Read Roberts + for (int i = 0; i < 2; i++) { + String s = params(fid, 10, errh, i != 0); + const uint8_t *data = s.udata(); + if (USHORT_AT(data) == 0) // design size == 0 + continue; + if (USHORT_AT(data + 2) == 0 // subfamily ID == 0 + && USHORT_AT(data + 6) == 0 // range start == 0 + && USHORT_AT(data + 8) == 0 // range end == 0 + && USHORT_AT(data + 4) == 0) // menu name ID == 0 + return s; + if (USHORT_AT(data) >= USHORT_AT(data + 6) // design size >= range start + && USHORT_AT(data) <= USHORT_AT(data + 8) // design size <= range end + && USHORT_AT(data + 6) < USHORT_AT(data + 8) // range start < range end + && USHORT_AT(data + 4) >= 256 // menu name ID >= 256 + && USHORT_AT(data + 4) <= 32767 // menu name ID <= 32767 + && name.english_name(USHORT_AT(data + 4))) // menu name ID is a name ID defined by the font + return s; + } + if (errh) + errh->error("no valid 'size' feature data in the 'size' feature"); + return String(); +} + int FeatureList::find(Tag tag, const Vector<int> &fids) const { @@ -486,7 +654,7 @@ FeatureList::lookups(int fid, Vector<int> &results, ErrorHandler *errh, bool cle if (_str.length() == 0) return -1; if (errh == 0) - errh = ErrorHandler::silent_handler(); + errh = ErrorHandler::ignore_handler(); const uint8_t *data = _str.udata(); int len = _str.length(); @@ -587,7 +755,7 @@ Coverage::Coverage(const String &str, ErrorHandler *errh, bool do_check) throw ( { _str.align(2); if (do_check) { - if (check(errh ? errh : ErrorHandler::silent_handler()) < 0) + if (check(errh ? errh : ErrorHandler::ignore_handler()) < 0) _str = String(); } else { // check()'s shorten-string side effect const uint8_t *data = _str.udata(); @@ -987,7 +1155,7 @@ ClassDef::ClassDef(const String &str, ErrorHandler *errh) throw () : _str(str) { _str.align(2); - if (check(errh ? errh : ErrorHandler::silent_handler()) < 0) + if (check(errh ? errh : ErrorHandler::ignore_handler()) < 0) _str = String(); } |