LCOV - code coverage report
Current view: directory - gfx/ots/src - ots.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 299 0 0.0 %
Date: 2012-06-02 Functions: 13 0 0.0 %

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

Generated by: LCOV version 1.7