LCOV - code coverage report
Current view: top level - gfx/ots/src - ots.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 417 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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_dec.h"
      18             : 
      19             : // The OpenType Font File
      20             : // http://www.microsoft.com/typography/otspec/cmap.htm
      21             : 
      22             : namespace {
      23             : 
      24             : // Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer
      25             : #define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE_MSG_TAG_(header, msg_, tag_)
      26             : #define OTS_FAILURE_MSG_HDR(msg_)      OTS_FAILURE_MSG_(header, msg_)
      27             : #define OTS_WARNING_MSG_HDR(msg_)      OTS_WARNING_MSG_(header, msg_)
      28             : 
      29             : 
      30             : struct OpenTypeTable {
      31             :   uint32_t tag;
      32             :   uint32_t chksum;
      33             :   uint32_t offset;
      34             :   uint32_t length;
      35             :   uint32_t uncompressed_length;
      36             : };
      37             : 
      38           0 : bool CheckTag(uint32_t tag_value) {
      39           0 :   for (unsigned i = 0; i < 4; ++i) {
      40           0 :     const uint32_t check = tag_value & 0xff;
      41           0 :     if (check < 32 || check > 126) {
      42           0 :       return false;  // non-ASCII character found.
      43             :     }
      44           0 :     tag_value >>= 8;
      45             :   }
      46           0 :   return true;
      47             : }
      48             : 
      49           0 : struct Arena {
      50             :  public:
      51           0 :   ~Arena() {
      52           0 :     for (std::vector<uint8_t*>::iterator
      53           0 :          i = hunks_.begin(); i != hunks_.end(); ++i) {
      54           0 :       delete[] *i;
      55             :     }
      56           0 :   }
      57             : 
      58           0 :   uint8_t* Allocate(size_t length) {
      59           0 :     uint8_t* p = new uint8_t[length];
      60           0 :     hunks_.push_back(p);
      61           0 :     return p;
      62             :   }
      63             : 
      64             :  private:
      65             :   std::vector<uint8_t*> hunks_;
      66             : };
      67             : 
      68             : const struct {
      69             :   uint32_t tag;
      70             :   bool (*parse)(ots::Font *font, const uint8_t *data, size_t length);
      71             :   bool (*serialise)(ots::OTSStream *out, ots::Font *font);
      72             :   bool (*should_serialise)(ots::Font *font);
      73             :   void (*reuse)(ots::Font *font, ots::Font *other);
      74             :   bool required;
      75             : } table_parsers[] = {
      76             :   { OTS_TAG('m','a','x','p'), ots::ots_maxp_parse, ots::ots_maxp_serialise,
      77             :     ots::ots_maxp_should_serialise, ots::ots_maxp_reuse, true },
      78             :   { OTS_TAG('h','e','a','d'), ots::ots_head_parse, ots::ots_head_serialise,
      79             :     ots::ots_head_should_serialise, ots::ots_head_reuse, true },
      80             :   { OTS_TAG('O','S','/','2'), ots::ots_os2_parse, ots::ots_os2_serialise,
      81             :     ots::ots_os2_should_serialise, ots::ots_os2_reuse, true },
      82             :   { OTS_TAG('c','m','a','p'), ots::ots_cmap_parse, ots::ots_cmap_serialise,
      83             :     ots::ots_cmap_should_serialise, ots::ots_cmap_reuse, true },
      84             :   { OTS_TAG('h','h','e','a'), ots::ots_hhea_parse, ots::ots_hhea_serialise,
      85             :     ots::ots_hhea_should_serialise, ots::ots_hhea_reuse, true },
      86             :   { OTS_TAG('h','m','t','x'), ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
      87             :     ots::ots_hmtx_should_serialise, ots::ots_hmtx_reuse, true },
      88             :   { OTS_TAG('n','a','m','e'), ots::ots_name_parse, ots::ots_name_serialise,
      89             :     ots::ots_name_should_serialise, ots::ots_name_reuse, true },
      90             :   { OTS_TAG('p','o','s','t'), ots::ots_post_parse, ots::ots_post_serialise,
      91             :     ots::ots_post_should_serialise, ots::ots_post_reuse, true },
      92             :   { OTS_TAG('l','o','c','a'), ots::ots_loca_parse, ots::ots_loca_serialise,
      93             :     ots::ots_loca_should_serialise, ots::ots_loca_reuse, false },
      94             :   { OTS_TAG('g','l','y','f'), ots::ots_glyf_parse, ots::ots_glyf_serialise,
      95             :     ots::ots_glyf_should_serialise, ots::ots_glyf_reuse, false },
      96             :   { OTS_TAG('C','F','F',' '), ots::ots_cff_parse, ots::ots_cff_serialise,
      97             :     ots::ots_cff_should_serialise, ots::ots_cff_reuse, false },
      98             :   { OTS_TAG('V','D','M','X'), ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
      99             :     ots::ots_vdmx_should_serialise, ots::ots_vdmx_reuse, false },
     100             :   { OTS_TAG('h','d','m','x'), ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
     101             :     ots::ots_hdmx_should_serialise, ots::ots_hdmx_reuse, false },
     102             :   { OTS_TAG('g','a','s','p'), ots::ots_gasp_parse, ots::ots_gasp_serialise,
     103             :     ots::ots_gasp_should_serialise, ots::ots_gasp_reuse, false },
     104             :   { OTS_TAG('c','v','t',' '), ots::ots_cvt_parse, ots::ots_cvt_serialise,
     105             :     ots::ots_cvt_should_serialise, ots::ots_cvt_reuse, false },
     106             :   { OTS_TAG('f','p','g','m'), ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
     107             :     ots::ots_fpgm_should_serialise, ots::ots_fpgm_reuse, false },
     108             :   { OTS_TAG('p','r','e','p'), ots::ots_prep_parse, ots::ots_prep_serialise,
     109             :     ots::ots_prep_should_serialise, ots::ots_prep_reuse, false },
     110             :   { OTS_TAG('L','T','S','H'), ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
     111             :     ots::ots_ltsh_should_serialise, ots::ots_ltsh_reuse, false },
     112             :   { OTS_TAG('V','O','R','G'), ots::ots_vorg_parse, ots::ots_vorg_serialise,
     113             :     ots::ots_vorg_should_serialise, ots::ots_vorg_reuse, false },
     114             :   { OTS_TAG('k','e','r','n'), ots::ots_kern_parse, ots::ots_kern_serialise,
     115             :     ots::ots_kern_should_serialise, ots::ots_kern_reuse, false },
     116             :   // We need to parse GDEF table in advance of parsing GSUB/GPOS tables
     117             :   // because they could refer GDEF table.
     118             :   { OTS_TAG('G','D','E','F'), ots::ots_gdef_parse, ots::ots_gdef_serialise,
     119             :     ots::ots_gdef_should_serialise, ots::ots_gdef_reuse, false },
     120             :   { OTS_TAG('G','P','O','S'), ots::ots_gpos_parse, ots::ots_gpos_serialise,
     121             :     ots::ots_gpos_should_serialise, ots::ots_gpos_reuse, false },
     122             :   { OTS_TAG('G','S','U','B'), ots::ots_gsub_parse, ots::ots_gsub_serialise,
     123             :     ots::ots_gsub_should_serialise, ots::ots_gsub_reuse, false },
     124             :   { OTS_TAG('v','h','e','a'), ots::ots_vhea_parse, ots::ots_vhea_serialise,
     125             :     ots::ots_vhea_should_serialise, ots::ots_vhea_reuse, false },
     126             :   { OTS_TAG('v','m','t','x'), ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
     127             :     ots::ots_vmtx_should_serialise, ots::ots_vmtx_reuse, false },
     128             :   { OTS_TAG('M','A','T','H'), ots::ots_math_parse, ots::ots_math_serialise,
     129             :     ots::ots_math_should_serialise, ots::ots_math_reuse, false },
     130             :   { 0, NULL, NULL, NULL, NULL, false },
     131             : };
     132             : 
     133             : bool ProcessGeneric(ots::OpenTypeFile *header,
     134             :                     ots::Font *font,
     135             :                     uint32_t signature,
     136             :                     ots::OTSStream *output,
     137             :                     const uint8_t *data, size_t length,
     138             :                     const std::vector<OpenTypeTable>& tables,
     139             :                     ots::Buffer& file);
     140             : 
     141           0 : bool ProcessTTF(ots::OpenTypeFile *header,
     142             :                 ots::Font *font,
     143             :                 ots::OTSStream *output, const uint8_t *data, size_t length,
     144             :                 uint32_t offset = 0) {
     145           0 :   ots::Buffer file(data + offset, length - offset);
     146             : 
     147           0 :   if (offset > length) {
     148           0 :     return OTS_FAILURE_MSG_HDR("offset beyond end of file");
     149             :   }
     150             : 
     151             :   // we disallow all files > 1GB in size for sanity.
     152           0 :   if (length > 1024 * 1024 * 1024) {
     153           0 :     return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
     154             :   }
     155             : 
     156           0 :   if (!file.ReadU32(&font->version)) {
     157           0 :     return OTS_FAILURE_MSG_HDR("error reading version tag");
     158             :   }
     159           0 :   if (!ots::IsValidVersionTag(font->version)) {
     160           0 :       return OTS_FAILURE_MSG_HDR("invalid version tag");
     161             :   }
     162             : 
     163           0 :   if (!file.ReadU16(&font->num_tables) ||
     164           0 :       !file.ReadU16(&font->search_range) ||
     165           0 :       !file.ReadU16(&font->entry_selector) ||
     166           0 :       !file.ReadU16(&font->range_shift)) {
     167           0 :     return OTS_FAILURE_MSG_HDR("error reading table directory search header");
     168             :   }
     169             : 
     170             :   // search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid
     171             :   // overflow num_tables is, at most, 2^16 / 16 = 2^12
     172           0 :   if (font->num_tables >= 4096 || font->num_tables < 1) {
     173           0 :     return OTS_FAILURE_MSG_HDR("excessive (or zero) number of tables");
     174             :   }
     175             : 
     176           0 :   unsigned max_pow2 = 0;
     177           0 :   while (1u << (max_pow2 + 1) <= font->num_tables) {
     178           0 :     max_pow2++;
     179             :   }
     180           0 :   const uint16_t expected_search_range = (1u << max_pow2) << 4;
     181             : 
     182             :   // Don't call ots_failure() here since ~25% of fonts (250+ fonts) in
     183             :   // http://www.princexml.com/fonts/ have unexpected search_range value.
     184           0 :   if (font->search_range != expected_search_range) {
     185           0 :     OTS_WARNING_MSG_HDR("bad search range");
     186           0 :     font->search_range = expected_search_range;  // Fix the value.
     187             :   }
     188             : 
     189             :   // entry_selector is Log2(maximum power of 2 <= numTables)
     190           0 :   if (font->entry_selector != max_pow2) {
     191           0 :     return OTS_FAILURE_MSG_HDR("incorrect entrySelector for table directory");
     192             :   }
     193             : 
     194             :   // range_shift is NumTables x 16-searchRange. We know that 16*num_tables
     195             :   // doesn't over flow because we range checked it above. Also, we know that
     196             :   // it's > font->search_range by construction of search_range.
     197             :   const uint16_t expected_range_shift =
     198           0 :       16 * font->num_tables - font->search_range;
     199           0 :   if (font->range_shift != expected_range_shift) {
     200           0 :     OTS_WARNING_MSG_HDR("bad range shift");
     201           0 :     font->range_shift = expected_range_shift;  // the same as above.
     202             :   }
     203             : 
     204             :   // Next up is the list of tables.
     205           0 :   std::vector<OpenTypeTable> tables;
     206             : 
     207           0 :   for (unsigned i = 0; i < font->num_tables; ++i) {
     208             :     OpenTypeTable table;
     209           0 :     if (!file.ReadU32(&table.tag) ||
     210           0 :         !file.ReadU32(&table.chksum) ||
     211           0 :         !file.ReadU32(&table.offset) ||
     212           0 :         !file.ReadU32(&table.length)) {
     213           0 :       return OTS_FAILURE_MSG_HDR("error reading table directory");
     214             :     }
     215             : 
     216           0 :     table.uncompressed_length = table.length;
     217           0 :     tables.push_back(table);
     218             :   }
     219             : 
     220           0 :   return ProcessGeneric(header, font, font->version, output, data, length,
     221           0 :                         tables, file);
     222             : }
     223             : 
     224           0 : bool ProcessTTC(ots::OpenTypeFile *header,
     225             :                 ots::OTSStream *output,
     226             :                 const uint8_t *data,
     227             :                 size_t length,
     228             :                 uint32_t index) {
     229           0 :   ots::Buffer file(data, length);
     230             : 
     231             :   // we disallow all files > 1GB in size for sanity.
     232           0 :   if (length > 1024 * 1024 * 1024) {
     233           0 :     return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
     234             :   }
     235             : 
     236             :   uint32_t ttc_tag;
     237           0 :   if (!file.ReadU32(&ttc_tag)) {
     238           0 :     return OTS_FAILURE_MSG_HDR("Error reading TTC tag");
     239             :   }
     240           0 :   if (ttc_tag != OTS_TAG('t','t','c','f')) {
     241           0 :     return OTS_FAILURE_MSG_HDR("Invalid TTC tag");
     242             :   }
     243             : 
     244             :   uint32_t ttc_version;
     245           0 :   if (!file.ReadU32(&ttc_version)) {
     246           0 :     return OTS_FAILURE_MSG_HDR("Error reading TTC version");
     247             :   }
     248           0 :   if (ttc_version != 0x00010000 && ttc_version != 0x00020000) {
     249           0 :     return OTS_FAILURE_MSG_HDR("Invalid TTC version");
     250             :   }
     251             : 
     252             :   uint32_t num_fonts;
     253           0 :   if (!file.ReadU32(&num_fonts)) {
     254           0 :     return OTS_FAILURE_MSG_HDR("Error reading number of TTC fonts");
     255             :   }
     256             :   // Limit the allowed number of subfonts to have same memory allocation.
     257           0 :   if (num_fonts > 0x10000) {
     258           0 :     return OTS_FAILURE_MSG_HDR("Too many fonts in TTC");
     259             :   }
     260             : 
     261           0 :   std::vector<uint32_t> offsets(num_fonts);
     262           0 :   for (unsigned i = 0; i < num_fonts; i++) {
     263           0 :     if (!file.ReadU32(&offsets[i])) {
     264           0 :       return OTS_FAILURE_MSG_HDR("Error reading offset to OffsetTable");
     265             :     }
     266             :   }
     267             : 
     268           0 :   if (ttc_version == 0x00020000) {
     269             :     // We don't care about these fields of the header:
     270             :     // uint32_t dsig_tag, dsig_length, dsig_offset
     271           0 :     if (!file.Skip(3 * 4)) {
     272           0 :       return OTS_FAILURE_MSG_HDR("Error reading DSIG offset and length in TTC font");
     273             :     }
     274             :   }
     275             : 
     276           0 :   if (index == static_cast<uint32_t>(-1)) {
     277           0 :     if (!output->WriteU32(ttc_tag) ||
     278           0 :         !output->WriteU32(0x00010000) ||
     279           0 :         !output->WriteU32(num_fonts) ||
     280           0 :         !output->Seek((3 + num_fonts) * 4)) {
     281           0 :       return OTS_FAILURE_MSG_HDR("Error writing output");
     282             :     }
     283             : 
     284             :     // Keep references to the fonts processed in the loop below, as we need
     285             :     // them for reused tables.
     286           0 :     std::vector<ots::Font> fonts(num_fonts, ots::Font(header));
     287             : 
     288           0 :     for (unsigned i = 0; i < num_fonts; i++) {
     289           0 :       uint32_t out_offset = output->Tell();
     290           0 :       if (!output->Seek((3 + i) * 4) ||
     291           0 :           !output->WriteU32(out_offset) ||
     292           0 :           !output->Seek(out_offset)) {
     293           0 :         return OTS_FAILURE_MSG_HDR("Error writing output");
     294             :       }
     295           0 :       if (!ProcessTTF(header, &fonts[i], output, data, length, offsets[i])) {
     296           0 :         return false;
     297             :       }
     298             :     }
     299             : 
     300           0 :     return true;
     301             :   } else {
     302           0 :     if (index >= num_fonts) {
     303           0 :       return OTS_FAILURE_MSG_HDR("Requested font index is bigger than the number of fonts in the TTC file");
     304             :     }
     305             : 
     306           0 :     ots::Font font(header);
     307           0 :     return ProcessTTF(header, &font, output, data, length, offsets[index]);
     308             :   }
     309             : }
     310             : 
     311           0 : bool ProcessWOFF(ots::OpenTypeFile *header,
     312             :                  ots::Font *font,
     313             :                  ots::OTSStream *output, const uint8_t *data, size_t length) {
     314           0 :   ots::Buffer file(data, length);
     315             : 
     316             :   // we disallow all files > 1GB in size for sanity.
     317           0 :   if (length > 1024 * 1024 * 1024) {
     318           0 :     return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
     319             :   }
     320             : 
     321             :   uint32_t woff_tag;
     322           0 :   if (!file.ReadU32(&woff_tag)) {
     323           0 :     return OTS_FAILURE_MSG_HDR("error reading WOFF marker");
     324             :   }
     325             : 
     326           0 :   if (woff_tag != OTS_TAG('w','O','F','F')) {
     327           0 :     return OTS_FAILURE_MSG_HDR("invalid WOFF marker");
     328             :   }
     329             : 
     330           0 :   if (!file.ReadU32(&font->version)) {
     331           0 :     return OTS_FAILURE_MSG_HDR("error reading version tag");
     332             :   }
     333           0 :   if (!ots::IsValidVersionTag(font->version)) {
     334           0 :     return OTS_FAILURE_MSG_HDR("invalid version tag");
     335             :   }
     336             : 
     337             :   uint32_t reported_length;
     338           0 :   if (!file.ReadU32(&reported_length) || length != reported_length) {
     339           0 :     return OTS_FAILURE_MSG_HDR("incorrect file size in WOFF header");
     340             :   }
     341             : 
     342           0 :   if (!file.ReadU16(&font->num_tables) || !font->num_tables) {
     343           0 :     return OTS_FAILURE_MSG_HDR("error reading number of tables");
     344             :   }
     345             : 
     346             :   uint16_t reserved_value;
     347           0 :   if (!file.ReadU16(&reserved_value) || reserved_value) {
     348           0 :     return OTS_FAILURE_MSG_HDR("error in reserved field of WOFF header");
     349             :   }
     350             : 
     351             :   uint32_t reported_total_sfnt_size;
     352           0 :   if (!file.ReadU32(&reported_total_sfnt_size)) {
     353           0 :     return OTS_FAILURE_MSG_HDR("error reading total sfnt size");
     354             :   }
     355             : 
     356             :   // We don't care about these fields of the header:
     357             :   //   uint16_t major_version, minor_version
     358           0 :   if (!file.Skip(2 * 2)) {
     359           0 :     return OTS_FAILURE_MSG_HDR("Failed to read 'majorVersion' or 'minorVersion'");
     360             :   }
     361             : 
     362             :   // Checks metadata block size.
     363             :   uint32_t meta_offset;
     364             :   uint32_t meta_length;
     365             :   uint32_t meta_length_orig;
     366           0 :   if (!file.ReadU32(&meta_offset) ||
     367           0 :       !file.ReadU32(&meta_length) ||
     368           0 :       !file.ReadU32(&meta_length_orig)) {
     369           0 :     return OTS_FAILURE_MSG_HDR("Failed to read header metadata block fields");
     370             :   }
     371           0 :   if (meta_offset) {
     372           0 :     if (meta_offset >= length || length - meta_offset < meta_length) {
     373           0 :       return OTS_FAILURE_MSG_HDR("Invalid metadata block offset or length");
     374             :     }
     375             :   }
     376             : 
     377             :   // Checks private data block size.
     378             :   uint32_t priv_offset;
     379             :   uint32_t priv_length;
     380           0 :   if (!file.ReadU32(&priv_offset) ||
     381           0 :       !file.ReadU32(&priv_length)) {
     382           0 :     return OTS_FAILURE_MSG_HDR("Failed to read header private block fields");
     383             :   }
     384           0 :   if (priv_offset) {
     385           0 :     if (priv_offset >= length || length - priv_offset < priv_length) {
     386           0 :       return OTS_FAILURE_MSG_HDR("Invalid private block offset or length");
     387             :     }
     388             :   }
     389             : 
     390             :   // Next up is the list of tables.
     391           0 :   std::vector<OpenTypeTable> tables;
     392             : 
     393           0 :   uint32_t first_index = 0;
     394           0 :   uint32_t last_index = 0;
     395             :   // Size of sfnt header plus size of table records.
     396           0 :   uint64_t total_sfnt_size = 12 + 16 * font->num_tables;
     397           0 :   for (unsigned i = 0; i < font->num_tables; ++i) {
     398             :     OpenTypeTable table;
     399           0 :     if (!file.ReadU32(&table.tag) ||
     400           0 :         !file.ReadU32(&table.offset) ||
     401           0 :         !file.ReadU32(&table.length) ||
     402           0 :         !file.ReadU32(&table.uncompressed_length) ||
     403           0 :         !file.ReadU32(&table.chksum)) {
     404           0 :       return OTS_FAILURE_MSG_HDR("error reading table directory");
     405             :     }
     406             : 
     407           0 :     total_sfnt_size += ots::Round4(table.uncompressed_length);
     408           0 :     if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) {
     409           0 :       return OTS_FAILURE_MSG_HDR("sfnt size overflow");
     410             :     }
     411           0 :     tables.push_back(table);
     412           0 :     if (i == 0 || tables[first_index].offset > table.offset)
     413           0 :       first_index = i;
     414           0 :     if (i == 0 || tables[last_index].offset < table.offset)
     415           0 :       last_index = i;
     416             :   }
     417             : 
     418           0 :   if (reported_total_sfnt_size != total_sfnt_size) {
     419           0 :     return OTS_FAILURE_MSG_HDR("uncompressed sfnt size mismatch");
     420             :   }
     421             : 
     422             :   // Table data must follow immediately after the header.
     423           0 :   if (tables[first_index].offset != ots::Round4(file.offset())) {
     424           0 :     return OTS_FAILURE_MSG_HDR("junk before tables in WOFF file");
     425             :   }
     426             : 
     427           0 :   if (tables[last_index].offset >= length ||
     428           0 :       length - tables[last_index].offset < tables[last_index].length) {
     429           0 :     return OTS_FAILURE_MSG_HDR("invalid table location/size");
     430             :   }
     431             :   // Blocks must follow immediately after the previous block.
     432             :   // (Except for padding with a maximum of three null bytes)
     433           0 :   uint64_t block_end = ots::Round4(
     434           0 :       static_cast<uint64_t>(tables[last_index].offset) +
     435           0 :       static_cast<uint64_t>(tables[last_index].length));
     436           0 :   if (block_end > std::numeric_limits<uint32_t>::max()) {
     437           0 :     return OTS_FAILURE_MSG_HDR("invalid table location/size");
     438             :   }
     439           0 :   if (meta_offset) {
     440           0 :     if (block_end != meta_offset) {
     441           0 :       return OTS_FAILURE_MSG_HDR("Invalid metadata block offset");
     442             :     }
     443           0 :     block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
     444           0 :                             static_cast<uint64_t>(meta_length));
     445           0 :     if (block_end > std::numeric_limits<uint32_t>::max()) {
     446           0 :       return OTS_FAILURE_MSG_HDR("Invalid metadata block length");
     447             :     }
     448             :   }
     449           0 :   if (priv_offset) {
     450           0 :     if (block_end != priv_offset) {
     451           0 :       return OTS_FAILURE_MSG_HDR("Invalid private block offset");
     452             :     }
     453           0 :     block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
     454           0 :                             static_cast<uint64_t>(priv_length));
     455           0 :     if (block_end > std::numeric_limits<uint32_t>::max()) {
     456           0 :       return OTS_FAILURE_MSG_HDR("Invalid private block length");
     457             :     }
     458             :   }
     459           0 :   if (block_end != ots::Round4(length)) {
     460           0 :     return OTS_FAILURE_MSG_HDR("File length mismatch (trailing junk?)");
     461             :   }
     462             : 
     463           0 :   return ProcessGeneric(header, font, woff_tag, output, data, length, tables, file);
     464             : }
     465             : 
     466           0 : bool ProcessWOFF2(ots::OpenTypeFile *header,
     467             :                   ots::OTSStream *output,
     468             :                   const uint8_t *data,
     469             :                   size_t length,
     470             :                   uint32_t index) {
     471           0 :   size_t decompressed_size = woff2::ComputeWOFF2FinalSize(data, length);
     472             : 
     473           0 :   if (decompressed_size == 0) {
     474           0 :     return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is set to 0");
     475             :   }
     476             :   // decompressed font must be <= 30MB
     477           0 :   if (decompressed_size > 30 * 1024 * 1024) {
     478           0 :     return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 font exceeds 30MB");
     479             :   }
     480             : 
     481           0 :   std::string buf(decompressed_size, 0);
     482           0 :   woff2::WOFF2StringOut out(&buf);
     483           0 :   if (!woff2::ConvertWOFF2ToTTF(data, length, &out)) {
     484           0 :     return OTS_FAILURE_MSG_HDR("Failed to convert WOFF 2.0 font to SFNT");
     485             :   }
     486           0 :   const uint8_t *decompressed = reinterpret_cast<const uint8_t*>(buf.data());
     487             : 
     488           0 :   if (data[4] == 't' && data[5] == 't' && data[6] == 'c' && data[7] == 'f') {
     489           0 :     return ProcessTTC(header, output, decompressed, out.Size(), index);
     490             :   } else {
     491           0 :     ots::Font font(header);
     492           0 :     return ProcessTTF(header, &font, output, decompressed, out.Size());
     493             :   }
     494             : }
     495             : 
     496           0 : ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
     497           0 :   ots::TableAction action = header->context->GetTableAction(tag);
     498             : 
     499           0 :   if (action == ots::TABLE_ACTION_DEFAULT) {
     500           0 :     action = ots::TABLE_ACTION_DROP;
     501             : 
     502           0 :     for (unsigned i = 0; ; ++i) {
     503           0 :       if (table_parsers[i].parse == NULL) break;
     504             : 
     505           0 :       if (table_parsers[i].tag == tag) {
     506           0 :         action = ots::TABLE_ACTION_SANITIZE;
     507           0 :         break;
     508             :       }
     509             :     }
     510             :   }
     511             : 
     512           0 :   assert(action != ots::TABLE_ACTION_DEFAULT); // Should never return this.
     513           0 :   return action;
     514             : }
     515             : 
     516           0 : bool GetTableData(const uint8_t *data,
     517             :                   const OpenTypeTable& table,
     518             :                   Arena *arena,
     519             :                   size_t *table_length,
     520             :                   const uint8_t **table_data) {
     521           0 :   if (table.uncompressed_length != table.length) {
     522             :     // Compressed table. Need to uncompress into memory first.
     523           0 :     *table_length = table.uncompressed_length;
     524           0 :     *table_data = (*arena).Allocate(*table_length);
     525           0 :     uLongf dest_len = *table_length;
     526           0 :     int r = uncompress((Bytef*) *table_data, &dest_len,
     527           0 :                        data + table.offset, table.length);
     528           0 :     if (r != Z_OK || dest_len != *table_length) {
     529           0 :       return false;
     530             :     }
     531             :   } else {
     532             :     // Uncompressed table. We can process directly from memory.
     533           0 :     *table_data = data + table.offset;
     534           0 :     *table_length = table.length;
     535             :   }
     536             : 
     537           0 :   return true;
     538             : }
     539             : 
     540           0 : bool ProcessGeneric(ots::OpenTypeFile *header,
     541             :                     ots::Font *font,
     542             :                     uint32_t signature,
     543             :                     ots::OTSStream *output,
     544             :                     const uint8_t *data, size_t length,
     545             :                     const std::vector<OpenTypeTable>& tables,
     546             :                     ots::Buffer& file) {
     547           0 :   const size_t data_offset = file.offset();
     548             : 
     549           0 :   uint32_t uncompressed_sum = 0;
     550             : 
     551           0 :   for (unsigned i = 0; i < font->num_tables; ++i) {
     552             :     // the tables must be sorted by tag (when taken as big-endian numbers).
     553             :     // This also remove the possibility of duplicate tables.
     554           0 :     if (i) {
     555           0 :       const uint32_t this_tag = tables[i].tag;
     556           0 :       const uint32_t prev_tag = tables[i - 1].tag;
     557           0 :       if (this_tag <= prev_tag) {
     558           0 :         OTS_WARNING_MSG_HDR("Table directory is not correctly ordered");
     559             :       }
     560             :     }
     561             : 
     562             :     // all tag names must be built from printable ASCII characters
     563           0 :     if (!CheckTag(tables[i].tag)) {
     564           0 :       return OTS_FAILURE_MSG_TAG("invalid table tag", tables[i].tag);
     565             :     }
     566             : 
     567             :     // tables must be 4-byte aligned
     568           0 :     if (tables[i].offset & 3) {
     569           0 :       return OTS_FAILURE_MSG_TAG("misaligned table", tables[i].tag);
     570             :     }
     571             : 
     572             :     // and must be within the file
     573           0 :     if (tables[i].offset < data_offset || tables[i].offset >= length) {
     574           0 :       return OTS_FAILURE_MSG_TAG("invalid table offset", tables[i].tag);
     575             :     }
     576             :     // disallow all tables with a zero length
     577           0 :     if (tables[i].length < 1) {
     578             :       // Note: malayalam.ttf has zero length CVT table...
     579           0 :       return OTS_FAILURE_MSG_TAG("zero-length table", tables[i].tag);
     580             :     }
     581             :     // disallow all tables with a length > 1GB
     582           0 :     if (tables[i].length > 1024 * 1024 * 1024) {
     583           0 :       return OTS_FAILURE_MSG_TAG("table length exceeds 1GB", tables[i].tag);
     584             :     }
     585             :     // disallow tables where the uncompressed size is < the compressed size.
     586           0 :     if (tables[i].uncompressed_length < tables[i].length) {
     587           0 :       return OTS_FAILURE_MSG_TAG("invalid compressed table", tables[i].tag);
     588             :     }
     589           0 :     if (tables[i].uncompressed_length > tables[i].length) {
     590             :       // We'll probably be decompressing this table.
     591             : 
     592             :       // disallow all tables which uncompress to > 30 MB
     593           0 :       if (tables[i].uncompressed_length > 30 * 1024 * 1024) {
     594           0 :         return OTS_FAILURE_MSG_TAG("uncompressed length exceeds 30MB", tables[i].tag);
     595             :       }
     596           0 :       if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
     597           0 :         return OTS_FAILURE_MSG_TAG("overflow of uncompressed sum", tables[i].tag);
     598             :       }
     599             : 
     600           0 :       uncompressed_sum += tables[i].uncompressed_length;
     601             :     }
     602             :     // since we required that the file be < 1GB in length, and that the table
     603             :     // length is < 1GB, the following addtion doesn't overflow
     604           0 :     uint32_t end_byte = tables[i].offset + tables[i].length;
     605             :     // Tables in the WOFF file must be aligned 4-byte boundary.
     606           0 :     if (signature == OTS_TAG('w','O','F','F')) {
     607           0 :         end_byte = ots::Round4(end_byte);
     608             :     }
     609           0 :     if (!end_byte || end_byte > length) {
     610           0 :       return OTS_FAILURE_MSG_TAG("table overruns end of file", tables[i].tag);
     611             :     }
     612             :   }
     613             : 
     614             :   // All decompressed tables uncompressed must be <= 30MB.
     615           0 :   if (uncompressed_sum > 30 * 1024 * 1024) {
     616           0 :     return OTS_FAILURE_MSG_HDR("uncompressed sum exceeds 30MB");
     617             :   }
     618             : 
     619           0 :   std::map<uint32_t, OpenTypeTable> table_map;
     620           0 :   for (unsigned i = 0; i < font->num_tables; ++i) {
     621           0 :     table_map[tables[i].tag] = tables[i];
     622             :   }
     623             : 
     624             :   // check that the tables are not overlapping.
     625           0 :   std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
     626           0 :   for (unsigned i = 0; i < font->num_tables; ++i) {
     627             :     overlap_checker.push_back(
     628           0 :         std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */));
     629             :     overlap_checker.push_back(
     630           0 :         std::make_pair(tables[i].offset + tables[i].length,
     631           0 :                        static_cast<uint8_t>(0) /* end */));
     632             :   }
     633           0 :   std::sort(overlap_checker.begin(), overlap_checker.end());
     634           0 :   int overlap_count = 0;
     635           0 :   for (unsigned i = 0; i < overlap_checker.size(); ++i) {
     636           0 :     overlap_count += (overlap_checker[i].second ? 1 : -1);
     637           0 :     if (overlap_count > 1) {
     638           0 :       return OTS_FAILURE_MSG_HDR("overlapping tables");
     639             :     }
     640             :   }
     641             : 
     642           0 :   Arena arena;
     643             : 
     644           0 :   for (unsigned i = 0; ; ++i) {
     645           0 :     if (table_parsers[i].parse == NULL) break;
     646             : 
     647           0 :     uint32_t tag = table_parsers[i].tag;
     648           0 :     const std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.find(tag);
     649             : 
     650           0 :     ots::TableAction action = GetTableAction(header, tag);
     651           0 :     if (it == table_map.end()) {
     652           0 :       if (table_parsers[i].required && action == ots::TABLE_ACTION_SANITIZE) {
     653           0 :         return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].tag);
     654             :       }
     655           0 :       continue;
     656             :     }
     657             : 
     658           0 :     uint32_t input_offset = it->second.offset;
     659           0 :     const ots::TableMap::const_iterator ot = header->tables.find(input_offset);
     660           0 :     if (ot == header->tables.end()) {
     661             :       const uint8_t* table_data;
     662             :       size_t table_length;
     663             : 
     664           0 :       if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
     665           0 :         return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
     666             :       }
     667             : 
     668           0 :       if (action == ots::TABLE_ACTION_SANITIZE &&
     669           0 :           !table_parsers[i].parse(font, table_data, table_length)) {
     670           0 :         return OTS_FAILURE();
     671             :       }
     672           0 :     } else if (action == ots::TABLE_ACTION_SANITIZE) {
     673           0 :       table_parsers[i].reuse(font, ot->second.first);
     674             :     }
     675           0 :   }
     676             : 
     677           0 :   if (font->cff) {
     678             :     // font with PostScript glyph
     679           0 :     if (font->version != OTS_TAG('O','T','T','O')) {
     680           0 :       return OTS_FAILURE_MSG_HDR("wrong font version for PostScript glyph data");
     681             :     }
     682           0 :     if (font->glyf || font->loca) {
     683             :       // mixing outline formats is not recommended
     684           0 :       return OTS_FAILURE_MSG_HDR("font contains both PS and TT glyphs");
     685             :     }
     686             :   } else {
     687           0 :     if (!font->glyf || !font->loca) {
     688             :       // No TrueType glyph found.
     689             : #define PASSTHRU_TABLE(tag_) (table_map.find(tag_) != table_map.end() && \
     690             :                               GetTableAction(header, tag_) == ots::TABLE_ACTION_PASSTHRU)
     691             :       // We don't sanitise bitmap table, but don't reject bitmap-only fonts if
     692             :       // we keep the tables.
     693           0 :       if (!PASSTHRU_TABLE(OTS_TAG('C','B','D','T')) ||
     694           0 :           !PASSTHRU_TABLE(OTS_TAG('C','B','L','C'))) {
     695           0 :         return OTS_FAILURE_MSG_HDR("no supported glyph shapes table(s) present");
     696             :       }
     697             : #undef PASSTHRU_TABLE
     698             :     }
     699             :   }
     700             : 
     701           0 :   uint16_t num_output_tables = 0;
     702           0 :   for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
     703           0 :        it != table_map.end(); ++it) {
     704           0 :     ots::TableAction action = GetTableAction(header, it->first);
     705           0 :     if (action == ots::TABLE_ACTION_PASSTHRU) {
     706           0 :       num_output_tables++;
     707             :     } else {
     708           0 :       for (unsigned i = 0; table_parsers[i].parse != NULL; ++i) {
     709           0 :         if (table_parsers[i].tag == it->first &&
     710           0 :             table_parsers[i].should_serialise(font)) {
     711           0 :           num_output_tables++;
     712           0 :           break;
     713             :         }
     714             :       }
     715             :     }
     716             :   }
     717             : 
     718           0 :   uint16_t max_pow2 = 0;
     719           0 :   while (1u << (max_pow2 + 1) <= num_output_tables) {
     720           0 :     max_pow2++;
     721             :   }
     722           0 :   const uint16_t output_search_range = (1u << max_pow2) << 4;
     723             : 
     724             :   // most of the errors here are highly unlikely - they'd only occur if the
     725             :   // output stream returns a failure, e.g. lack of space to write
     726           0 :   output->ResetChecksum();
     727           0 :   if (!output->WriteU32(font->version) ||
     728           0 :       !output->WriteU16(num_output_tables) ||
     729           0 :       !output->WriteU16(output_search_range) ||
     730           0 :       !output->WriteU16(max_pow2) ||
     731           0 :       !output->WriteU16((num_output_tables << 4) - output_search_range)) {
     732           0 :     return OTS_FAILURE_MSG_HDR("error writing output");
     733             :   }
     734           0 :   const uint32_t offset_table_chksum = output->chksum();
     735             : 
     736           0 :   const size_t table_record_offset = output->Tell();
     737           0 :   if (!output->Pad(16 * num_output_tables)) {
     738           0 :     return OTS_FAILURE_MSG_HDR("error writing output");
     739             :   }
     740             : 
     741           0 :   std::vector<ots::OutputTable> out_tables;
     742             : 
     743           0 :   size_t head_table_offset = 0;
     744           0 :   for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
     745           0 :        it != table_map.end(); ++it) {
     746           0 :     uint32_t input_offset = it->second.offset;
     747           0 :     const ots::TableMap::const_iterator ot = header->tables.find(input_offset);
     748           0 :     if (ot != header->tables.end()) {
     749           0 :       ots::OutputTable out = ot->second.second;
     750           0 :       if (out.tag == OTS_TAG('h','e','a','d')) {
     751           0 :         head_table_offset = out.offset;
     752             :       }
     753           0 :       out_tables.push_back(out);
     754             :     } else {
     755             :       ots::OutputTable out;
     756           0 :       out.tag = it->first;
     757           0 :       out.offset = output->Tell();
     758             : 
     759           0 :       if (out.tag == OTS_TAG('h','e','a','d')) {
     760           0 :         head_table_offset = out.offset;
     761             :       }
     762             : 
     763           0 :       ots::TableAction action = GetTableAction(header, it->first);
     764           0 :       if (action == ots::TABLE_ACTION_PASSTHRU) {
     765           0 :         output->ResetChecksum();
     766             :         const uint8_t* table_data;
     767             :         size_t table_length;
     768             : 
     769           0 :         if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
     770           0 :           return OTS_FAILURE_MSG_HDR("Failed to uncompress table");
     771             :         }
     772             : 
     773           0 :         if (!output->Write(table_data, table_length)) {
     774           0 :           return OTS_FAILURE_MSG_HDR("Failed to serialize table");
     775             :         }
     776             : 
     777           0 :         const size_t end_offset = output->Tell();
     778           0 :         if (end_offset <= out.offset) {
     779             :           // paranoid check. |end_offset| is supposed to be greater than the offset,
     780             :           // as long as the Tell() interface is implemented correctly.
     781           0 :           return OTS_FAILURE_MSG_HDR("error writing output");
     782             :         }
     783           0 :         out.length = end_offset - out.offset;
     784             : 
     785             :         // align tables to four bytes
     786           0 :         if (!output->Pad((4 - (end_offset & 3)) % 4)) {
     787           0 :           return OTS_FAILURE_MSG_HDR("error writing output");
     788             :         }
     789           0 :         out.chksum = output->chksum();
     790           0 :         out_tables.push_back(out);
     791           0 :         header->tables[input_offset] = std::make_pair(font, out);
     792             :       } else {
     793           0 :         for (unsigned i = 0; table_parsers[i].parse != NULL; ++i) {
     794           0 :           if (table_parsers[i].tag == it->first &&
     795           0 :               table_parsers[i].should_serialise(font)) {
     796           0 :             output->ResetChecksum();
     797           0 :             if (!table_parsers[i].serialise(output, font)) {
     798           0 :               return OTS_FAILURE_MSG_TAG("failed to serialize table", table_parsers[i].tag);
     799             :             }
     800             : 
     801           0 :             const size_t end_offset = output->Tell();
     802           0 :             if (end_offset <= out.offset) {
     803             :               // paranoid check. |end_offset| is supposed to be greater than the offset,
     804             :               // as long as the Tell() interface is implemented correctly.
     805           0 :               return OTS_FAILURE_MSG_HDR("error writing output");
     806             :             }
     807           0 :             out.length = end_offset - out.offset;
     808             : 
     809             :             // align tables to four bytes
     810           0 :             if (!output->Pad((4 - (end_offset & 3)) % 4)) {
     811           0 :               return OTS_FAILURE_MSG_HDR("error writing output");
     812             :             }
     813           0 :             out.chksum = output->chksum();
     814           0 :             out_tables.push_back(out);
     815           0 :             header->tables[input_offset] = std::make_pair(font, out);
     816             : 
     817           0 :             break;
     818             :           }
     819             :         }
     820             :       }
     821             :     }
     822             :   }
     823             : 
     824           0 :   const size_t end_of_file = output->Tell();
     825             : 
     826             :   // Need to sort the output tables for inclusion in the file
     827           0 :   std::sort(out_tables.begin(), out_tables.end());
     828           0 :   if (!output->Seek(table_record_offset)) {
     829           0 :     return OTS_FAILURE_MSG_HDR("error writing output");
     830             :   }
     831             : 
     832           0 :   output->ResetChecksum();
     833           0 :   uint32_t tables_chksum = 0;
     834           0 :   for (unsigned i = 0; i < out_tables.size(); ++i) {
     835           0 :     if (!output->WriteU32(out_tables[i].tag) ||
     836           0 :         !output->WriteU32(out_tables[i].chksum) ||
     837           0 :         !output->WriteU32(out_tables[i].offset) ||
     838           0 :         !output->WriteU32(out_tables[i].length)) {
     839           0 :       return OTS_FAILURE_MSG_HDR("error writing output");
     840             :     }
     841           0 :     tables_chksum += out_tables[i].chksum;
     842             :   }
     843           0 :   const uint32_t table_record_chksum = output->chksum();
     844             : 
     845             :   // http://www.microsoft.com/typography/otspec/otff.htm
     846             :   const uint32_t file_chksum
     847           0 :       = offset_table_chksum + tables_chksum + table_record_chksum;
     848           0 :   const uint32_t chksum_magic = static_cast<uint32_t>(0xb1b0afba) - file_chksum;
     849             : 
     850             :   // seek into the 'head' table and write in the checksum magic value
     851           0 :   if (!head_table_offset) {
     852           0 :     return OTS_FAILURE_MSG_HDR("internal error!");
     853             :   }
     854           0 :   if (!output->Seek(head_table_offset + 8)) {
     855           0 :     return OTS_FAILURE_MSG_HDR("error writing output");
     856             :   }
     857           0 :   if (!output->WriteU32(chksum_magic)) {
     858           0 :     return OTS_FAILURE_MSG_HDR("error writing output");
     859             :   }
     860             : 
     861           0 :   if (!output->Seek(end_of_file)) {
     862           0 :     return OTS_FAILURE_MSG_HDR("error writing output");
     863             :   }
     864             : 
     865           0 :   return true;
     866             : }
     867             : 
     868             : }  // namespace
     869             : 
     870             : namespace ots {
     871             : 
     872           0 : bool IsValidVersionTag(uint32_t tag) {
     873           0 :   return tag == 0x000010000 ||
     874             :          // OpenType fonts with CFF data have 'OTTO' tag.
     875           0 :          tag == OTS_TAG('O','T','T','O') ||
     876             :          // Older Mac fonts might have 'true' or 'typ1' tag.
     877           0 :          tag == OTS_TAG('t','r','u','e') ||
     878           0 :          tag == OTS_TAG('t','y','p','1');
     879             : }
     880             : 
     881           0 : bool OTSContext::Process(OTSStream *output,
     882             :                          const uint8_t *data,
     883             :                          size_t length,
     884             :                          uint32_t index) {
     885           0 :   OpenTypeFile header;
     886           0 :   Font font(&header);
     887           0 :   header.context = this;
     888             : 
     889           0 :   if (length < 4) {
     890           0 :     return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
     891             :   }
     892             : 
     893             :   bool result;
     894           0 :   if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
     895           0 :     result = ProcessWOFF(&header, &font, output, data, length);
     896           0 :   } else if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == '2') {
     897           0 :     result = ProcessWOFF2(&header, output, data, length, index);
     898           0 :   } else if (data[0] == 't' && data[1] == 't' && data[2] == 'c' && data[3] == 'f') {
     899           0 :     result = ProcessTTC(&header, output, data, length, index);
     900             :   } else {
     901           0 :     result = ProcessTTF(&header, &font, output, data, length);
     902             :   }
     903             : 
     904           0 :   return result;
     905             : }
     906             : 
     907             : }  // namespace ots

Generated by: LCOV version 1.13