Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ots.h"
      6 
      7 #include <sys/types.h>
      8 #include <zlib.h>
      9 
     10 #include <algorithm>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <limits>
     14 #include <map>
     15 #include <vector>
     16 
     17 #include "woff2.h"
     18 
     19 // The OpenType Font File
     20 // http://www.microsoft.com/typography/otspec/cmap.htm
     21 
     22 namespace {
     23 
     24 bool g_debug_output = true;
     25 bool g_enable_woff2 = false;
     26 
     27 struct OpenTypeTable {
     28   uint32_t tag;
     29   uint32_t chksum;
     30   uint32_t offset;
     31   uint32_t length;
     32   uint32_t uncompressed_length;
     33 };
     34 
     35 bool CheckTag(uint32_t tag_value) {
     36   for (unsigned i = 0; i < 4; ++i) {
     37     const uint32_t check = tag_value & 0xff;
     38     if (check < 32 || check > 126) {
     39       return false;  // non-ASCII character found.
     40     }
     41     tag_value >>= 8;
     42   }
     43   return true;
     44 }
     45 
     46 uint32_t Tag(const char *tag_str) {
     47   uint32_t ret;
     48   std::memcpy(&ret, tag_str, 4);
     49   return ret;
     50 }
     51 
     52 struct OutputTable {
     53   uint32_t tag;
     54   size_t offset;
     55   size_t length;
     56   uint32_t chksum;
     57 
     58   static bool SortByTag(const OutputTable& a, const OutputTable& b) {
     59     const uint32_t atag = ntohl(a.tag);
     60     const uint32_t btag = ntohl(b.tag);
     61     return atag < btag;
     62   }
     63 };
     64 
     65 struct Arena {
     66  public:
     67   ~Arena() {
     68     for (std::vector<uint8_t*>::iterator
     69          i = hunks_.begin(); i != hunks_.end(); ++i) {
     70       delete[] *i;
     71     }
     72   }
     73 
     74   uint8_t* Allocate(size_t length) {
     75     uint8_t* p = new uint8_t[length];
     76     hunks_.push_back(p);
     77     return p;
     78   }
     79 
     80  private:
     81   std::vector<uint8_t*> hunks_;
     82 };
     83 
     84 const struct {
     85   const char* tag;
     86   bool (*parse)(ots::OpenTypeFile *otf, const uint8_t *data, size_t length);
     87   bool (*serialise)(ots::OTSStream *out, ots::OpenTypeFile *file);
     88   bool (*should_serialise)(ots::OpenTypeFile *file);
     89   void (*free)(ots::OpenTypeFile *file);
     90   bool required;
     91 } table_parsers[] = {
     92   { "maxp", ots::ots_maxp_parse, ots::ots_maxp_serialise,
     93     ots::ots_maxp_should_serialise, ots::ots_maxp_free, true },
     94   { "head", ots::ots_head_parse, ots::ots_head_serialise,
     95     ots::ots_head_should_serialise, ots::ots_head_free, true },
     96   { "OS/2", ots::ots_os2_parse, ots::ots_os2_serialise,
     97     ots::ots_os2_should_serialise, ots::ots_os2_free, true },
     98   { "cmap", ots::ots_cmap_parse, ots::ots_cmap_serialise,
     99     ots::ots_cmap_should_serialise, ots::ots_cmap_free, true },
    100   { "hhea", ots::ots_hhea_parse, ots::ots_hhea_serialise,
    101     ots::ots_hhea_should_serialise, ots::ots_hhea_free, true },
    102   { "hmtx", ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
    103     ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true },
    104   { "name", ots::ots_name_parse, ots::ots_name_serialise,
    105     ots::ots_name_should_serialise, ots::ots_name_free, true },
    106   { "post", ots::ots_post_parse, ots::ots_post_serialise,
    107     ots::ots_post_should_serialise, ots::ots_post_free, true },
    108   { "loca", ots::ots_loca_parse, ots::ots_loca_serialise,
    109     ots::ots_loca_should_serialise, ots::ots_loca_free, false },
    110   { "glyf", ots::ots_glyf_parse, ots::ots_glyf_serialise,
    111     ots::ots_glyf_should_serialise, ots::ots_glyf_free, false },
    112   { "CFF ", ots::ots_cff_parse, ots::ots_cff_serialise,
    113     ots::ots_cff_should_serialise, ots::ots_cff_free, false },
    114   { "VDMX", ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
    115     ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false },
    116   { "hdmx", ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
    117     ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false },
    118   { "gasp", ots::ots_gasp_parse, ots::ots_gasp_serialise,
    119     ots::ots_gasp_should_serialise, ots::ots_gasp_free, false },
    120   { "cvt ", ots::ots_cvt_parse, ots::ots_cvt_serialise,
    121     ots::ots_cvt_should_serialise, ots::ots_cvt_free, false },
    122   { "fpgm", ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
    123     ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false },
    124   { "prep", ots::ots_prep_parse, ots::ots_prep_serialise,
    125     ots::ots_prep_should_serialise, ots::ots_prep_free, false },
    126   { "LTSH", ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
    127     ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false },
    128   { "VORG", ots::ots_vorg_parse, ots::ots_vorg_serialise,
    129     ots::ots_vorg_should_serialise, ots::ots_vorg_free, false },
    130   { "kern", ots::ots_kern_parse, ots::ots_kern_serialise,
    131     ots::ots_kern_should_serialise, ots::ots_kern_free, false },
    132   // We need to parse GDEF table in advance of parsing GSUB/GPOS tables
    133   // because they could refer GDEF table.
    134   { "GDEF", ots::ots_gdef_parse, ots::ots_gdef_serialise,
    135     ots::ots_gdef_should_serialise, ots::ots_gdef_free, false },
    136   { "GPOS", ots::ots_gpos_parse, ots::ots_gpos_serialise,
    137     ots::ots_gpos_should_serialise, ots::ots_gpos_free, false },
    138   { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise,
    139     ots::ots_gsub_should_serialise, ots::ots_gsub_free, false },
    140   { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise,
    141     ots::ots_vhea_should_serialise, ots::ots_vhea_free, false },
    142   { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
    143     ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false },
    144   { "MATH", ots::ots_math_parse, ots::ots_math_serialise,
    145     ots::ots_math_should_serialise, ots::ots_math_free, false },
    146   // TODO(bashi): Support mort, base, and jstf tables.
    147   { 0, NULL, NULL, NULL, NULL, false },
    148 };
    149 
    150 bool ProcessGeneric(ots::OpenTypeFile *header,
    151                     uint32_t signature,
    152                     ots::OTSStream *output,
    153                     const uint8_t *data, size_t length,
    154                     const std::vector<OpenTypeTable>& tables,
    155                     ots::Buffer& file);
    156 
    157 bool ProcessTTF(ots::OpenTypeFile *header,
    158                 ots::OTSStream *output, const uint8_t *data, size_t length) {
    159   ots::Buffer file(data, length);
    160 
    161   // we disallow all files > 1GB in size for sanity.
    162   if (length > 1024 * 1024 * 1024) {
    163     return OTS_FAILURE();
    164   }
    165 
    166   if (!file.ReadTag(&header->version)) {
    167     return OTS_FAILURE();
    168   }
    169   if (!ots::IsValidVersionTag(header->version)) {
    170       return OTS_FAILURE();
    171   }
    172 
    173   if (!file.ReadU16(&header->num_tables) ||
    174       !file.ReadU16(&header->search_range) ||
    175       !file.ReadU16(&header->entry_selector) ||
    176       !file.ReadU16(&header->range_shift)) {
    177     return OTS_FAILURE();
    178   }
    179 
    180   // search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid
    181   // overflow num_tables is, at most, 2^16 / 16 = 2^12
    182   if (header->num_tables >= 4096 || header->num_tables < 1) {
    183     return OTS_FAILURE();
    184   }
    185 
    186   unsigned max_pow2 = 0;
    187   while (1u << (max_pow2 + 1) <= header->num_tables) {
    188     max_pow2++;
    189   }
    190   const uint16_t expected_search_range = (1u << max_pow2) << 4;
    191 
    192   // Don't call ots_failure() here since ~25% of fonts (250+ fonts) in
    193   // http://www.princexml.com/fonts/ have unexpected search_range value.
    194   if (header->search_range != expected_search_range) {
    195     OTS_WARNING("bad search range");
    196     header->search_range = expected_search_range;  // Fix the value.
    197   }
    198 
    199   // entry_selector is Log2(maximum power of 2 <= numTables)
    200   if (header->entry_selector != max_pow2) {
    201     return OTS_FAILURE();
    202   }
    203 
    204   // range_shift is NumTables x 16-searchRange. We know that 16*num_tables
    205   // doesn't over flow because we range checked it above. Also, we know that
    206   // it's > header->search_range by construction of search_range.
    207   const uint32_t expected_range_shift
    208       = 16 * header->num_tables - header->search_range;
    209   if (header->range_shift != expected_range_shift) {
    210     OTS_WARNING("bad range shift");
    211     header->range_shift = expected_range_shift;  // the same as above.
    212   }
    213 
    214   // Next up is the list of tables.
    215   std::vector<OpenTypeTable> tables;
    216 
    217   for (unsigned i = 0; i < header->num_tables; ++i) {
    218     OpenTypeTable table;
    219     if (!file.ReadTag(&table.tag) ||
    220         !file.ReadU32(&table.chksum) ||
    221         !file.ReadU32(&table.offset) ||
    222         !file.ReadU32(&table.length)) {
    223       return OTS_FAILURE();
    224     }
    225 
    226     table.uncompressed_length = table.length;
    227     tables.push_back(table);
    228   }
    229 
    230   return ProcessGeneric(header, header->version, output, data, length,
    231                         tables, file);
    232 }
    233 
    234 bool ProcessWOFF(ots::OpenTypeFile *header,
    235                  ots::OTSStream *output, const uint8_t *data, size_t length) {
    236   ots::Buffer file(data, length);
    237 
    238   // we disallow all files > 1GB in size for sanity.
    239   if (length > 1024 * 1024 * 1024) {
    240     return OTS_FAILURE();
    241   }
    242 
    243   uint32_t woff_tag;
    244   if (!file.ReadTag(&woff_tag)) {
    245     return OTS_FAILURE();
    246   }
    247 
    248   if (woff_tag != Tag("wOFF")) {
    249     return OTS_FAILURE();
    250   }
    251 
    252   if (!file.ReadTag(&header->version)) {
    253     return OTS_FAILURE();
    254   }
    255   if (!ots::IsValidVersionTag(header->version)) {
    256       return OTS_FAILURE();
    257   }
    258 
    259   header->search_range = 0;
    260   header->entry_selector = 0;
    261   header->range_shift = 0;
    262 
    263   uint32_t reported_length;
    264   if (!file.ReadU32(&reported_length) || length != reported_length) {
    265     return OTS_FAILURE();
    266   }
    267 
    268   if (!file.ReadU16(&header->num_tables) || !header->num_tables) {
    269     return OTS_FAILURE();
    270   }
    271 
    272   uint16_t reserved_value;
    273   if (!file.ReadU16(&reserved_value) || reserved_value) {
    274     return OTS_FAILURE();
    275   }
    276 
    277   uint32_t reported_total_sfnt_size;
    278   if (!file.ReadU32(&reported_total_sfnt_size)) {
    279     return OTS_FAILURE();
    280   }
    281 
    282   // We don't care about these fields of the header:
    283   //   uint16_t major_version, minor_version
    284   if (!file.Skip(2 * 2)) {
    285     return OTS_FAILURE();
    286   }
    287 
    288   // Checks metadata block size.
    289   uint32_t meta_offset;
    290   uint32_t meta_length;
    291   uint32_t meta_length_orig;
    292   if (!file.ReadU32(&meta_offset) ||
    293       !file.ReadU32(&meta_length) ||
    294       !file.ReadU32(&meta_length_orig)) {
    295     return OTS_FAILURE();
    296   }
    297   if (meta_offset) {
    298     if (meta_offset >= length || length - meta_offset < meta_length) {
    299       return OTS_FAILURE();
    300     }
    301   }
    302 
    303   // Checks private data block size.
    304   uint32_t priv_offset;
    305   uint32_t priv_length;
    306   if (!file.ReadU32(&priv_offset) ||
    307       !file.ReadU32(&priv_length)) {
    308     return OTS_FAILURE();
    309   }
    310   if (priv_offset) {
    311     if (priv_offset >= length || length - priv_offset < priv_length) {
    312       return OTS_FAILURE();
    313     }
    314   }
    315 
    316   // Next up is the list of tables.
    317   std::vector<OpenTypeTable> tables;
    318 
    319   uint32_t first_index = 0;
    320   uint32_t last_index = 0;
    321   // Size of sfnt header plus size of table records.
    322   uint64_t total_sfnt_size = 12 + 16 * header->num_tables;
    323   for (unsigned i = 0; i < header->num_tables; ++i) {
    324     OpenTypeTable table;
    325     if (!file.ReadTag(&table.tag) ||
    326         !file.ReadU32(&table.offset) ||
    327         !file.ReadU32(&table.length) ||
    328         !file.ReadU32(&table.uncompressed_length) ||
    329         !file.ReadU32(&table.chksum)) {
    330       return OTS_FAILURE();
    331     }
    332 
    333     total_sfnt_size += ots::Round4(table.uncompressed_length);
    334     if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) {
    335       return OTS_FAILURE();
    336     }
    337     tables.push_back(table);
    338     if (i == 0 || tables[first_index].offset > table.offset)
    339       first_index = i;
    340     if (i == 0 || tables[last_index].offset < table.offset)
    341       last_index = i;
    342   }
    343 
    344   if (reported_total_sfnt_size != total_sfnt_size) {
    345     return OTS_FAILURE();
    346   }
    347 
    348   // Table data must follow immediately after the header.
    349   if (tables[first_index].offset != ots::Round4(file.offset())) {
    350     return OTS_FAILURE();
    351   }
    352 
    353   if (tables[last_index].offset >= length ||
    354       length - tables[last_index].offset < tables[last_index].length) {
    355     return OTS_FAILURE();
    356   }
    357   // Blocks must follow immediately after the previous block.
    358   // (Except for padding with a maximum of three null bytes)
    359   uint64_t block_end = ots::Round4(
    360       static_cast<uint64_t>(tables[last_index].offset) +
    361       static_cast<uint64_t>(tables[last_index].length));
    362   if (block_end > std::numeric_limits<uint32_t>::max()) {
    363     return OTS_FAILURE();
    364   }
    365   if (meta_offset) {
    366     if (block_end != meta_offset) {
    367       return OTS_FAILURE();
    368     }
    369     block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
    370                             static_cast<uint64_t>(meta_length));
    371     if (block_end > std::numeric_limits<uint32_t>::max()) {
    372       return OTS_FAILURE();
    373     }
    374   }
    375   if (priv_offset) {
    376     if (block_end != priv_offset) {
    377       return OTS_FAILURE();
    378     }
    379     block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
    380                             static_cast<uint64_t>(priv_length));
    381     if (block_end > std::numeric_limits<uint32_t>::max()) {
    382       return OTS_FAILURE();
    383     }
    384   }
    385   if (block_end != ots::Round4(length)) {
    386     return OTS_FAILURE();
    387   }
    388 
    389   return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
    390 }
    391 
    392 bool ProcessWOFF2(ots::OpenTypeFile *header,
    393                   ots::OTSStream *output, const uint8_t *data, size_t length) {
    394   size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
    395   if (decompressed_size == 0) {
    396     return OTS_FAILURE();
    397   }
    398   // decompressed font must be <= 30MB
    399   if (decompressed_size > 30 * 1024 * 1024) {
    400     return OTS_FAILURE();
    401   }
    402 
    403   std::vector<uint8_t> decompressed_buffer(decompressed_size);
    404   if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size,
    405                               data, length)) {
    406     return OTS_FAILURE();
    407   }
    408   return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
    409 }
    410 
    411 bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
    412                     ots::OTSStream *output,
    413                     const uint8_t *data, size_t length,
    414                     const std::vector<OpenTypeTable>& tables,
    415                     ots::Buffer& file) {
    416   const size_t data_offset = file.offset();
    417 
    418   uint32_t uncompressed_sum = 0;
    419 
    420   for (unsigned i = 0; i < header->num_tables; ++i) {
    421     // the tables must be sorted by tag (when taken as big-endian numbers).
    422     // This also remove the possibility of duplicate tables.
    423     if (i) {
    424       const uint32_t this_tag = ntohl(tables[i].tag);
    425       const uint32_t prev_tag = ntohl(tables[i - 1].tag);
    426       if (this_tag <= prev_tag) {
    427         return OTS_FAILURE();
    428       }
    429     }
    430 
    431     // all tag names must be built from printable ASCII characters
    432     if (!CheckTag(tables[i].tag)) {
    433       return OTS_FAILURE();
    434     }
    435 
    436     // tables must be 4-byte aligned
    437     if (tables[i].offset & 3) {
    438       return OTS_FAILURE();
    439     }
    440 
    441     // and must be within the file
    442     if (tables[i].offset < data_offset || tables[i].offset >= length) {
    443       return OTS_FAILURE();
    444     }
    445     // disallow all tables with a zero length
    446     if (tables[i].length < 1) {
    447       // Note: malayalam.ttf has zero length CVT table...
    448       return OTS_FAILURE();
    449     }
    450     // disallow all tables with a length > 1GB
    451     if (tables[i].length > 1024 * 1024 * 1024) {
    452       return OTS_FAILURE();
    453     }
    454     // disallow tables where the uncompressed size is < the compressed size.
    455     if (tables[i].uncompressed_length < tables[i].length) {
    456       return OTS_FAILURE();
    457     }
    458     if (tables[i].uncompressed_length > tables[i].length) {
    459       // We'll probably be decompressing this table.
    460 
    461       // disallow all tables which uncompress to > 30 MB
    462       if (tables[i].uncompressed_length > 30 * 1024 * 1024) {
    463         return OTS_FAILURE();
    464       }
    465       if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
    466         return OTS_FAILURE();
    467       }
    468 
    469       uncompressed_sum += tables[i].uncompressed_length;
    470     }
    471     // since we required that the file be < 1GB in length, and that the table
    472     // length is < 1GB, the following addtion doesn't overflow
    473     uint32_t end_byte = tables[i].offset + tables[i].length;
    474     // Tables in the WOFF file must be aligned 4-byte boundary.
    475     if (signature == Tag("wOFF")) {
    476         end_byte = ots::Round4(end_byte);
    477     }
    478     if (!end_byte || end_byte > length) {
    479       return OTS_FAILURE();
    480     }
    481   }
    482 
    483   // All decompressed tables uncompressed must be <= 30MB.
    484   if (uncompressed_sum > 30 * 1024 * 1024) {
    485     return OTS_FAILURE();
    486   }
    487 
    488   std::map<uint32_t, OpenTypeTable> table_map;
    489   for (unsigned i = 0; i < header->num_tables; ++i) {
    490     table_map[tables[i].tag] = tables[i];
    491   }
    492 
    493   // check that the tables are not overlapping.
    494   std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
    495   for (unsigned i = 0; i < header->num_tables; ++i) {
    496     overlap_checker.push_back(
    497         std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */));
    498     overlap_checker.push_back(
    499         std::make_pair(tables[i].offset + tables[i].length,
    500                        static_cast<uint8_t>(0) /* end */));
    501   }
    502   std::sort(overlap_checker.begin(), overlap_checker.end());
    503   int overlap_count = 0;
    504   for (unsigned i = 0; i < overlap_checker.size(); ++i) {
    505     overlap_count += (overlap_checker[i].second ? 1 : -1);
    506     if (overlap_count > 1) {
    507       return OTS_FAILURE();
    508     }
    509   }
    510 
    511   Arena arena;
    512 
    513   for (unsigned i = 0; ; ++i) {
    514     if (table_parsers[i].parse == NULL) break;
    515 
    516     const std::map<uint32_t, OpenTypeTable>::const_iterator it
    517         = table_map.find(Tag(table_parsers[i].tag));
    518 
    519     if (it == table_map.end()) {
    520       if (table_parsers[i].required) {
    521         return OTS_FAILURE();
    522       }
    523       continue;
    524     }
    525 
    526     const uint8_t* table_data;
    527     size_t table_length;
    528 
    529     if (it->second.uncompressed_length != it->second.length) {
    530       // compressed table. Need to uncompress into memory first.
    531       table_length = it->second.uncompressed_length;
    532       table_data = arena.Allocate(table_length);
    533       uLongf dest_len = table_length;
    534       int r = uncompress((Bytef*) table_data, &dest_len,
    535                          data + it->second.offset, it->second.length);
    536       if (r != Z_OK || dest_len != table_length) {
    537         return OTS_FAILURE();
    538       }
    539     } else {
    540       // uncompressed table. We can process directly from memory.
    541       table_data = data + it->second.offset;
    542       table_length = it->second.length;
    543     }
    544 
    545     if (!table_parsers[i].parse(header, table_data, table_length)) {
    546       return OTS_FAILURE();
    547     }
    548   }
    549 
    550   if (header->cff) {
    551     // font with PostScript glyph
    552     if (header->version != Tag("OTTO")) {
    553       return OTS_FAILURE();
    554     }
    555     if (header->glyf || header->loca) {
    556       // mixing outline formats is not recommended
    557       return OTS_FAILURE();
    558     }
    559   } else {
    560     if (!header->glyf || !header->loca) {
    561       // No TrueType glyph found.
    562       // Note: bitmap-only fonts are not supported.
    563       return OTS_FAILURE();
    564     }
    565   }
    566 
    567   unsigned num_output_tables = 0;
    568   for (unsigned i = 0; ; ++i) {
    569     if (table_parsers[i].parse == NULL) {
    570       break;
    571     }
    572 
    573     if (table_parsers[i].should_serialise(header)) {
    574       num_output_tables++;
    575     }
    576   }
    577 
    578   unsigned max_pow2 = 0;
    579   while (1u << (max_pow2 + 1) <= num_output_tables) {
    580     max_pow2++;
    581   }
    582   const uint16_t output_search_range = (1u << max_pow2) << 4;
    583 
    584   output->ResetChecksum();
    585   if (!output->WriteTag(header->version) ||
    586       !output->WriteU16(num_output_tables) ||
    587       !output->WriteU16(output_search_range) ||
    588       !output->WriteU16(max_pow2) ||
    589       !output->WriteU16((num_output_tables << 4) - output_search_range)) {
    590     return OTS_FAILURE();
    591   }
    592   const uint32_t offset_table_chksum = output->chksum();
    593 
    594   const size_t table_record_offset = output->Tell();
    595   if (!output->Pad(16 * num_output_tables)) {
    596     return OTS_FAILURE();
    597   }
    598 
    599   std::vector<OutputTable> out_tables;
    600 
    601   size_t head_table_offset = 0;
    602   for (unsigned i = 0; ; ++i) {
    603     if (table_parsers[i].parse == NULL) {
    604       break;
    605     }
    606 
    607     if (!table_parsers[i].should_serialise(header)) {
    608       continue;
    609     }
    610 
    611     OutputTable out;
    612     uint32_t tag = Tag(table_parsers[i].tag);
    613     out.tag = tag;
    614     out.offset = output->Tell();
    615 
    616     output->ResetChecksum();
    617     if (tag == Tag("head")) {
    618       head_table_offset = out.offset;
    619     }
    620     if (!table_parsers[i].serialise(output, header)) {
    621       return OTS_FAILURE();
    622     }
    623 
    624     const size_t end_offset = output->Tell();
    625     if (end_offset <= out.offset) {
    626       // paranoid check. |end_offset| is supposed to be greater than the offset,
    627       // as long as the Tell() interface is implemented correctly.
    628       return OTS_FAILURE();
    629     }
    630     out.length = end_offset - out.offset;
    631 
    632     // align tables to four bytes
    633     if (!output->Pad((4 - (end_offset & 3)) % 4)) {
    634       return OTS_FAILURE();
    635     }
    636     out.chksum = output->chksum();
    637     out_tables.push_back(out);
    638   }
    639 
    640   const size_t end_of_file = output->Tell();
    641 
    642   // Need to sort the output tables for inclusion in the file
    643   std::sort(out_tables.begin(), out_tables.end(), OutputTable::SortByTag);
    644   if (!output->Seek(table_record_offset)) {
    645     return OTS_FAILURE();
    646   }
    647 
    648   output->ResetChecksum();
    649   uint32_t tables_chksum = 0;
    650   for (unsigned i = 0; i < out_tables.size(); ++i) {
    651     if (!output->WriteTag(out_tables[i].tag) ||
    652         !output->WriteU32(out_tables[i].chksum) ||
    653         !output->WriteU32(out_tables[i].offset) ||
    654         !output->WriteU32(out_tables[i].length)) {
    655       return OTS_FAILURE();
    656     }
    657     tables_chksum += out_tables[i].chksum;
    658   }
    659   const uint32_t table_record_chksum = output->chksum();
    660 
    661   // http://www.microsoft.com/typography/otspec/otff.htm
    662   const uint32_t file_chksum
    663       = offset_table_chksum + tables_chksum + table_record_chksum;
    664   const uint32_t chksum_magic = static_cast<uint32_t>(0xb1b0afba) - file_chksum;
    665 
    666   // seek into the 'head' table and write in the checksum magic value
    667   if (!head_table_offset) {
    668     return OTS_FAILURE();  // not reached.
    669   }
    670   if (!output->Seek(head_table_offset + 8)) {
    671     return OTS_FAILURE();
    672   }
    673   if (!output->WriteU32(chksum_magic)) {
    674     return OTS_FAILURE();
    675   }
    676 
    677   if (!output->Seek(end_of_file)) {
    678     return OTS_FAILURE();
    679   }
    680 
    681   return true;
    682 }
    683 
    684 }  // namespace
    685 
    686 namespace ots {
    687 
    688 bool IsValidVersionTag(uint32_t tag) {
    689   return tag == Tag("\x00\x01\x00\x00") ||
    690          // OpenType fonts with CFF data have 'OTTO' tag.
    691          tag == Tag("OTTO") ||
    692          // Older Mac fonts might have 'true' or 'typ1' tag.
    693          tag == Tag("true") ||
    694          tag == Tag("typ1");
    695 }
    696 
    697 void DisableDebugOutput() {
    698   g_debug_output = false;
    699 }
    700 
    701 void EnableWOFF2() {
    702   g_enable_woff2 = true;
    703 }
    704 
    705 bool Process(OTSStream *output, const uint8_t *data, size_t length) {
    706   OpenTypeFile header;
    707   if (length < 4) {
    708     return OTS_FAILURE();
    709   }
    710 
    711   bool result;
    712   if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
    713     result = ProcessWOFF(&header, output, data, length);
    714   } else if (g_enable_woff2 &&
    715              data[0] == 'w' && data[1] == 'O' && data[2] == 'F' &&
    716              data[3] == '2') {
    717     result = ProcessWOFF2(&header, output, data, length);
    718   } else {
    719     result = ProcessTTF(&header, output, data, length);
    720   }
    721 
    722   for (unsigned i = 0; ; ++i) {
    723     if (table_parsers[i].parse == NULL) break;
    724     table_parsers[i].free(&header);
    725   }
    726   return result;
    727 }
    728 
    729 #if !defined(_MSC_VER) && defined(OTS_DEBUG)
    730 bool Failure(const char *f, int l, const char *fn) {
    731   if (g_debug_output) {
    732     std::fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
    733     std::fflush(stderr);
    734   }
    735   return false;
    736 }
    737 
    738 void Warning(const char *f, int l, const char *format, ...) {
    739   if (g_debug_output) {
    740     std::fprintf(stderr, "WARNING at %s:%d: ", f, l);
    741     std::va_list va;
    742     va_start(va, format);
    743     std::vfprintf(stderr, format, va);
    744     va_end(va);
    745     std::fprintf(stderr, "\n");
    746     std::fflush(stderr);
    747   }
    748 }
    749 #endif
    750 
    751 }  // namespace ots
    752