LCOV - code coverage report
Current view: top level - gfx/ots/src - cmap.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 572 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 10 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 "cmap.h"
       6             : 
       7             : #include <algorithm>
       8             : #include <set>
       9             : #include <utility>
      10             : #include <vector>
      11             : 
      12             : #include "maxp.h"
      13             : #include "os2.h"
      14             : 
      15             : // cmap - Character To Glyph Index Mapping Table
      16             : // http://www.microsoft.com/typography/otspec/cmap.htm
      17             : 
      18             : #define TABLE_NAME "cmap"
      19             : 
      20             : namespace {
      21             : 
      22             : struct CMAPSubtableHeader {
      23             :   uint16_t platform;
      24             :   uint16_t encoding;
      25             :   uint32_t offset;
      26             :   uint16_t format;
      27             :   uint32_t length;
      28             :   uint32_t language;
      29             : };
      30             : 
      31             : struct Subtable314Range {
      32             :   uint16_t start_range;
      33             :   uint16_t end_range;
      34             :   int16_t id_delta;
      35             :   uint16_t id_range_offset;
      36             :   uint32_t id_range_offset_offset;
      37             : };
      38             : 
      39             : // Glyph array size for the Mac Roman (format 0) table.
      40             : const size_t kFormat0ArraySize = 256;
      41             : 
      42             : // The upper limit of the Unicode code point.
      43             : const uint32_t kUnicodeUpperLimit = 0x10FFFF;
      44             : 
      45             : // The maximum number of UVS records (See below).
      46             : const uint32_t kMaxCMAPSelectorRecords = 259;
      47             : // The range of UVSes are:
      48             : //   0x180B-0x180D (3 code points)
      49             : //   0xFE00-0xFE0F (16 code points)
      50             : //   0xE0100-0xE01EF (240 code points)
      51             : const uint32_t kMongolianVSStart = 0x180B;
      52             : const uint32_t kMongolianVSEnd = 0x180D;
      53             : const uint32_t kVSStart = 0xFE00;
      54             : const uint32_t kVSEnd = 0xFE0F;
      55             : const uint32_t kIVSStart = 0xE0100;
      56             : const uint32_t kIVSEnd = 0xE01EF;
      57             : const uint32_t kUVSUpperLimit = 0xFFFFFF;
      58             : 
      59             : // Parses Format 4 tables
      60           0 : bool ParseFormat4(ots::Font *font, int platform, int encoding,
      61             :               const uint8_t *data, size_t length, uint16_t num_glyphs) {
      62           0 :   ots::Buffer subtable(data, length);
      63             : 
      64             :   // 0.3.4, 3.0.4 or 3.1.4 subtables are complex and, rather than expanding the
      65             :   // whole thing and recompacting it, we validate it and include it verbatim
      66             :   // in the output.
      67             : 
      68           0 :   if (!font->os2) {
      69           0 :     return OTS_FAILURE_MSG("Required OS/2 table missing");
      70             :   }
      71             : 
      72           0 :   if (!subtable.Skip(4)) {
      73           0 :     return OTS_FAILURE_MSG("Can't read 4 bytes at start of cmap format 4 subtable");
      74             :   }
      75           0 :   uint16_t language = 0;
      76           0 :   if (!subtable.ReadU16(&language)) {
      77           0 :     return OTS_FAILURE_MSG("Can't read language");
      78             :   }
      79           0 :   if (language) {
      80             :     // Platform ID 3 (windows) subtables should have language '0'.
      81           0 :     return OTS_FAILURE_MSG("Languages should be 0 (%d)", language);
      82             :   }
      83             : 
      84             :   uint16_t segcountx2, search_range, entry_selector, range_shift;
      85           0 :   segcountx2 = search_range = entry_selector = range_shift = 0;
      86           0 :   if (!subtable.ReadU16(&segcountx2) ||
      87           0 :       !subtable.ReadU16(&search_range) ||
      88           0 :       !subtable.ReadU16(&entry_selector) ||
      89           0 :       !subtable.ReadU16(&range_shift)) {
      90           0 :     return OTS_FAILURE_MSG("Failed to read subcmap structure");
      91             :   }
      92             : 
      93           0 :   if (segcountx2 & 1 || search_range & 1) {
      94           0 :     return OTS_FAILURE_MSG("Bad subcmap structure");
      95             :   }
      96           0 :   const uint16_t segcount = segcountx2 >> 1;
      97             :   // There must be at least one segment according the spec.
      98           0 :   if (segcount < 1) {
      99           0 :     return OTS_FAILURE_MSG("Segcount < 1 (%d)", segcount);
     100             :   }
     101             : 
     102             :   // log2segcount is the maximal x s.t. 2^x < segcount
     103           0 :   unsigned log2segcount = 0;
     104           0 :   while (1u << (log2segcount + 1) <= segcount) {
     105           0 :     log2segcount++;
     106             :   }
     107             : 
     108           0 :   const uint16_t expected_search_range = 2 * 1u << log2segcount;
     109           0 :   if (expected_search_range != search_range) {
     110           0 :     return OTS_FAILURE_MSG("expected search range != search range (%d != %d)", expected_search_range, search_range);
     111             :   }
     112             : 
     113           0 :   if (entry_selector != log2segcount) {
     114           0 :     return OTS_FAILURE_MSG("entry selector != log2(segement count) (%d != %d)", entry_selector, log2segcount);
     115             :   }
     116             : 
     117           0 :   const uint16_t expected_range_shift = segcountx2 - search_range;
     118           0 :   if (range_shift != expected_range_shift) {
     119           0 :     return OTS_FAILURE_MSG("unexpected range shift (%d != %d)", range_shift, expected_range_shift);
     120             :   }
     121             : 
     122           0 :   std::vector<Subtable314Range> ranges(segcount);
     123             : 
     124           0 :   for (unsigned i = 0; i < segcount; ++i) {
     125           0 :     if (!subtable.ReadU16(&ranges[i].end_range)) {
     126           0 :       return OTS_FAILURE_MSG("Failed to read segment %d", i);
     127             :     }
     128             :   }
     129             : 
     130             :   uint16_t padding;
     131           0 :   if (!subtable.ReadU16(&padding)) {
     132           0 :     return OTS_FAILURE_MSG("Failed to read cmap subtable segment padding");
     133             :   }
     134           0 :   if (padding) {
     135           0 :     return OTS_FAILURE_MSG("Non zero cmap subtable segment padding (%d)", padding);
     136             :   }
     137             : 
     138           0 :   for (unsigned i = 0; i < segcount; ++i) {
     139           0 :     if (!subtable.ReadU16(&ranges[i].start_range)) {
     140           0 :       return OTS_FAILURE_MSG("Failed to read segment start range %d", i);
     141             :     }
     142             :   }
     143           0 :   for (unsigned i = 0; i < segcount; ++i) {
     144           0 :     if (!subtable.ReadS16(&ranges[i].id_delta)) {
     145           0 :       return OTS_FAILURE_MSG("Failed to read segment delta %d", i);
     146             :     }
     147             :   }
     148           0 :   for (unsigned i = 0; i < segcount; ++i) {
     149           0 :     ranges[i].id_range_offset_offset = subtable.offset();
     150           0 :     if (!subtable.ReadU16(&ranges[i].id_range_offset)) {
     151           0 :       return OTS_FAILURE_MSG("Failed to read segment range offset %d", i);
     152             :     }
     153             : 
     154           0 :     if (ranges[i].id_range_offset & 1) {
     155             :       // Some font generators seem to put 65535 on id_range_offset
     156             :       // for 0xFFFF-0xFFFF range.
     157             :       // (e.g., many fonts in http://www.princexml.com/fonts/)
     158           0 :       if (i == segcount - 1u) {
     159           0 :         OTS_WARNING("bad id_range_offset");
     160           0 :         ranges[i].id_range_offset = 0;
     161             :         // The id_range_offset value in the transcoded font will not change
     162             :         // since this table is not actually "transcoded" yet.
     163             :       } else {
     164           0 :         return OTS_FAILURE_MSG("Bad segment offset (%d)", ranges[i].id_range_offset);
     165             :       }
     166             :     }
     167             :   }
     168             : 
     169             :   // ranges must be ascending order, based on the end_code. Ranges may not
     170             :   // overlap.
     171           0 :   for (unsigned i = 1; i < segcount; ++i) {
     172           0 :     if ((i == segcount - 1u) &&
     173           0 :         (ranges[i - 1].start_range == 0xffff) &&
     174           0 :         (ranges[i - 1].end_range == 0xffff) &&
     175           0 :         (ranges[i].start_range == 0xffff) &&
     176           0 :         (ranges[i].end_range == 0xffff)) {
     177             :       // Some fonts (e.g., Germania.ttf) have multiple 0xffff terminators.
     178             :       // We'll accept them as an exception.
     179           0 :       OTS_WARNING("multiple 0xffff terminators found");
     180           0 :       continue;
     181             :     }
     182             : 
     183             :     // Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have
     184             :     // unsorted table...
     185           0 :     if (ranges[i].end_range <= ranges[i - 1].end_range) {
     186           0 :       return OTS_FAILURE_MSG("Out of order end range (%d <= %d)", ranges[i].end_range, ranges[i-1].end_range);
     187             :     }
     188           0 :     if (ranges[i].start_range <= ranges[i - 1].end_range) {
     189           0 :       return OTS_FAILURE_MSG("out of order start range (%d <= %d)", ranges[i].start_range, ranges[i-1].end_range);
     190             :     }
     191             : 
     192             :     // On many fonts, the value of {first, last}_char_index are incorrect.
     193             :     // Fix them.
     194           0 :     if (font->os2->first_char_index != 0xFFFF &&
     195           0 :         ranges[i].start_range != 0xFFFF &&
     196           0 :         font->os2->first_char_index > ranges[i].start_range) {
     197           0 :       font->os2->first_char_index = ranges[i].start_range;
     198             :     }
     199           0 :     if (font->os2->last_char_index != 0xFFFF &&
     200           0 :         ranges[i].end_range != 0xFFFF &&
     201           0 :         font->os2->last_char_index < ranges[i].end_range) {
     202           0 :       font->os2->last_char_index = ranges[i].end_range;
     203             :     }
     204             :   }
     205             : 
     206             :   // The last range must end at 0xffff
     207           0 :   if (ranges[segcount - 1].start_range != 0xffff || ranges[segcount - 1].end_range != 0xffff) {
     208           0 :     return OTS_FAILURE_MSG("Final segment start and end must be 0xFFFF (0x%04X-0x%04X)",
     209             :                            ranges[segcount - 1].start_range, ranges[segcount - 1].end_range);
     210             :   }
     211             : 
     212             :   // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of
     213             :   // each code-point defined in the table and make sure that they are all valid
     214             :   // glyphs and that we don't access anything out-of-bounds.
     215           0 :   for (unsigned i = 0; i < segcount; ++i) {
     216           0 :     for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) {
     217           0 :       const uint16_t code_point = static_cast<uint16_t>(cp);
     218           0 :       if (ranges[i].id_range_offset == 0) {
     219             :         // this is explictly allowed to overflow in the spec
     220           0 :         const uint16_t glyph = code_point + ranges[i].id_delta;
     221           0 :         if (glyph >= num_glyphs) {
     222           0 :           return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
     223             :         }
     224             :       } else {
     225           0 :         const uint16_t range_delta = code_point - ranges[i].start_range;
     226             :         // this might seem odd, but it's true. The offset is relative to the
     227             :         // location of the offset value itself.
     228           0 :         const uint32_t glyph_id_offset = ranges[i].id_range_offset_offset +
     229           0 :                                          ranges[i].id_range_offset +
     230           0 :                                          range_delta * 2;
     231             :         // We need to be able to access a 16-bit value from this offset
     232           0 :         if (glyph_id_offset + 1 >= length) {
     233           0 :           return OTS_FAILURE_MSG("bad glyph id offset (%d > %ld)", glyph_id_offset, length);
     234             :         }
     235             :         uint16_t glyph;
     236           0 :         std::memcpy(&glyph, data + glyph_id_offset, 2);
     237           0 :         glyph = ntohs(glyph);
     238           0 :         if (glyph >= num_glyphs) {
     239           0 :           return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
     240             :         }
     241             :       }
     242             :     }
     243             :   }
     244             : 
     245             :   // We accept the table.
     246             :   // TODO(yusukes): transcode the subtable.
     247           0 :   if (platform == 3 && encoding == 0) {
     248           0 :     font->cmap->subtable_3_0_4_data = data;
     249           0 :     font->cmap->subtable_3_0_4_length = length;
     250           0 :   } else if (platform == 3 && encoding == 1) {
     251           0 :     font->cmap->subtable_3_1_4_data = data;
     252           0 :     font->cmap->subtable_3_1_4_length = length;
     253           0 :   } else if (platform == 0 && encoding == 3) {
     254           0 :     font->cmap->subtable_0_3_4_data = data;
     255           0 :     font->cmap->subtable_0_3_4_length = length;
     256             :   } else {
     257           0 :     return OTS_FAILURE_MSG("Unknown cmap subtable type (platform=%d, encoding=%d)", platform, encoding);
     258             :   }
     259             : 
     260           0 :   return true;
     261             : }
     262             : 
     263           0 : bool Parse31012(ots::Font *font,
     264             :                 const uint8_t *data, size_t length, uint16_t num_glyphs) {
     265           0 :   ots::Buffer subtable(data, length);
     266             : 
     267             :   // Format 12 tables are simple. We parse these and fully serialise them
     268             :   // later.
     269             : 
     270           0 :   if (!subtable.Skip(8)) {
     271           0 :     return OTS_FAILURE_MSG("failed to skip the first 8 bytes of format 12 subtable");
     272             :   }
     273           0 :   uint32_t language = 0;
     274           0 :   if (!subtable.ReadU32(&language)) {
     275           0 :     return OTS_FAILURE_MSG("can't read format 12 subtable language");
     276             :   }
     277           0 :   if (language) {
     278           0 :     return OTS_FAILURE_MSG("format 12 subtable language should be zero (%d)", language);
     279             :   }
     280             : 
     281           0 :   uint32_t num_groups = 0;
     282           0 :   if (!subtable.ReadU32(&num_groups)) {
     283           0 :     return OTS_FAILURE_MSG("can't read number of format 12 subtable groups");
     284             :   }
     285           0 :   if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
     286           0 :     return OTS_FAILURE_MSG("Bad format 12 subtable group count %d", num_groups);
     287             :   }
     288             : 
     289             :   std::vector<ots::OpenTypeCMAPSubtableRange> &groups
     290           0 :       = font->cmap->subtable_3_10_12;
     291           0 :   groups.resize(num_groups);
     292             : 
     293           0 :   for (unsigned i = 0; i < num_groups; ++i) {
     294           0 :     if (!subtable.ReadU32(&groups[i].start_range) ||
     295           0 :         !subtable.ReadU32(&groups[i].end_range) ||
     296           0 :         !subtable.ReadU32(&groups[i].start_glyph_id)) {
     297           0 :       return OTS_FAILURE_MSG("can't read format 12 subtable group");
     298             :     }
     299             : 
     300           0 :     if (groups[i].start_range > kUnicodeUpperLimit ||
     301           0 :         groups[i].end_range > kUnicodeUpperLimit ||
     302           0 :         groups[i].start_glyph_id > 0xFFFF) {
     303           0 :       return OTS_FAILURE_MSG("bad format 12 subtable group (startCharCode=0x%4X, endCharCode=0x%4X, startGlyphID=%d)",
     304             :                              groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
     305             :     }
     306             : 
     307             :     // We assert that the glyph value is within range. Because of the range
     308             :     // limits, above, we don't need to worry about overflow.
     309           0 :     if (groups[i].end_range < groups[i].start_range) {
     310           0 :       return OTS_FAILURE_MSG("format 12 subtable group endCharCode before startCharCode (0x%4X < 0x%4X)",
     311             :                              groups[i].end_range, groups[i].start_range);
     312             :     }
     313           0 :     if ((groups[i].end_range - groups[i].start_range) +
     314           0 :         groups[i].start_glyph_id > num_glyphs) {
     315           0 :       return OTS_FAILURE_MSG("bad format 12 subtable group startGlyphID (%d)", groups[i].start_glyph_id);
     316             :     }
     317             :   }
     318             : 
     319             :   // the groups must be sorted by start code and may not overlap
     320           0 :   for (unsigned i = 1; i < num_groups; ++i) {
     321           0 :     if (groups[i].start_range <= groups[i - 1].start_range) {
     322           0 :       return OTS_FAILURE_MSG("out of order format 12 subtable group (startCharCode=0x%4X <= startCharCode=0x%4X of previous group)",
     323             :                              groups[i].start_range, groups[i-1].start_range);
     324             :     }
     325           0 :     if (groups[i].start_range <= groups[i - 1].end_range) {
     326           0 :       return OTS_FAILURE_MSG("overlapping format 12 subtable groups (startCharCode=0x%4X <= endCharCode=0x%4X of previous group)",
     327             :                              groups[i].start_range, groups[i-1].end_range);
     328             :     }
     329             :   }
     330             : 
     331           0 :   return true;
     332             : }
     333             : 
     334           0 : bool Parse31013(ots::Font *font,
     335             :                 const uint8_t *data, size_t length, uint16_t num_glyphs) {
     336           0 :   ots::Buffer subtable(data, length);
     337             : 
     338             :   // Format 13 tables are simple. We parse these and fully serialise them
     339             :   // later.
     340             : 
     341           0 :   if (!subtable.Skip(8)) {
     342           0 :     return OTS_FAILURE_MSG("Bad cmap subtable length");
     343             :   }
     344           0 :   uint32_t language = 0;
     345           0 :   if (!subtable.ReadU32(&language)) {
     346           0 :     return OTS_FAILURE_MSG("Can't read cmap subtable language");
     347             :   }
     348           0 :   if (language) {
     349           0 :     return OTS_FAILURE_MSG("Cmap subtable language should be zero but is %d", language);
     350             :   }
     351             : 
     352           0 :   uint32_t num_groups = 0;
     353           0 :   if (!subtable.ReadU32(&num_groups)) {
     354           0 :     return OTS_FAILURE_MSG("Can't read number of groups in a cmap subtable");
     355             :   }
     356             : 
     357             :   // We limit the number of groups in the same way as in 3.10.12 tables. See
     358             :   // the comment there in
     359           0 :   if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
     360           0 :     return OTS_FAILURE_MSG("Bad format 13 subtable group count %d", num_groups);
     361             :   }
     362             : 
     363             :   std::vector<ots::OpenTypeCMAPSubtableRange> &groups
     364           0 :       = font->cmap->subtable_3_10_13;
     365           0 :   groups.resize(num_groups);
     366             : 
     367           0 :   for (unsigned i = 0; i < num_groups; ++i) {
     368           0 :     if (!subtable.ReadU32(&groups[i].start_range) ||
     369           0 :         !subtable.ReadU32(&groups[i].end_range) ||
     370           0 :         !subtable.ReadU32(&groups[i].start_glyph_id)) {
     371           0 :       return OTS_FAILURE_MSG("Can't read subrange structure in a cmap subtable");
     372             :     }
     373             : 
     374             :     // We conservatively limit all of the values to protect some parsers from
     375             :     // overflows
     376           0 :     if (groups[i].start_range > kUnicodeUpperLimit ||
     377           0 :         groups[i].end_range > kUnicodeUpperLimit ||
     378           0 :         groups[i].start_glyph_id > 0xFFFF) {
     379           0 :       return OTS_FAILURE_MSG("Bad subrange with start_range=%d, end_range=%d, start_glyph_id=%d", groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
     380             :     }
     381             : 
     382           0 :     if (groups[i].start_glyph_id >= num_glyphs) {
     383           0 :       return OTS_FAILURE_MSG("Subrange starting glyph id too high (%d > %d)", groups[i].start_glyph_id, num_glyphs);
     384             :     }
     385             :   }
     386             : 
     387             :   // the groups must be sorted by start code and may not overlap
     388           0 :   for (unsigned i = 1; i < num_groups; ++i) {
     389           0 :     if (groups[i].start_range <= groups[i - 1].start_range) {
     390           0 :       return OTS_FAILURE_MSG("Overlapping subrange starts (%d >= %d)", groups[i]. start_range, groups[i-1].start_range);
     391             :     }
     392           0 :     if (groups[i].start_range <= groups[i - 1].end_range) {
     393           0 :       return OTS_FAILURE_MSG("Overlapping subranges (%d <= %d)", groups[i].start_range, groups[i-1].end_range);
     394             :     }
     395             :   }
     396             : 
     397           0 :   return true;
     398             : }
     399             : 
     400           0 : bool Parse0514(ots::Font *font,
     401             :                const uint8_t *data, size_t length, uint16_t num_glyphs) {
     402             :   // Unicode Variation Selector table
     403           0 :   ots::Buffer subtable(data, length);
     404             : 
     405             :   // Format 14 tables are simple. We parse these and fully serialise them
     406             :   // later.
     407             : 
     408             :   // Skip format (USHORT) and length (ULONG)
     409           0 :   if (!subtable.Skip(6)) {
     410           0 :     return OTS_FAILURE_MSG("Can't read start of cmap subtable");
     411             :   }
     412             : 
     413           0 :   uint32_t num_records = 0;
     414           0 :   if (!subtable.ReadU32(&num_records)) {
     415           0 :     return OTS_FAILURE_MSG("Can't read number of records in cmap subtable");
     416             :   }
     417           0 :   if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) {
     418           0 :     return OTS_FAILURE_MSG("Bad format 14 subtable records count %d", num_records);
     419             :   }
     420             : 
     421             :   std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records
     422           0 :       = font->cmap->subtable_0_5_14;
     423           0 :   records.resize(num_records);
     424             : 
     425           0 :   for (unsigned i = 0; i < num_records; ++i) {
     426           0 :     if (!subtable.ReadU24(&records[i].var_selector) ||
     427           0 :         !subtable.ReadU32(&records[i].default_offset) ||
     428           0 :         !subtable.ReadU32(&records[i].non_default_offset)) {
     429           0 :       return OTS_FAILURE_MSG("Can't read record structure of record %d in cmap subtale", i);
     430             :     }
     431             :     // Checks the value of variation selector
     432           0 :     if (!((records[i].var_selector >= kMongolianVSStart &&
     433           0 :            records[i].var_selector <= kMongolianVSEnd) ||
     434           0 :           (records[i].var_selector >= kVSStart &&
     435           0 :            records[i].var_selector <= kVSEnd) ||
     436           0 :           (records[i].var_selector >= kIVSStart &&
     437           0 :            records[i].var_selector <= kIVSEnd))) {
     438           0 :       return OTS_FAILURE_MSG("Bad record variation selector (%04X) in record %i", records[i].var_selector, i);
     439             :     }
     440           0 :     if (i > 0 &&
     441           0 :         records[i-1].var_selector >= records[i].var_selector) {
     442           0 :       return OTS_FAILURE_MSG("Out of order variation selector (%04X >= %04X) in record %d", records[i-1].var_selector, records[i].var_selector, i);
     443             :     }
     444             : 
     445             :     // Checks offsets
     446           0 :     if (!records[i].default_offset && !records[i].non_default_offset) {
     447           0 :       return OTS_FAILURE_MSG("No default aoffset in variation selector record %d", i);
     448             :     }
     449           0 :     if (records[i].default_offset &&
     450           0 :         records[i].default_offset >= length) {
     451           0 :       return OTS_FAILURE_MSG("Default offset too high (%d >= %ld) in record %d", records[i].default_offset, length, i);
     452             :     }
     453           0 :     if (records[i].non_default_offset &&
     454           0 :         records[i].non_default_offset >= length) {
     455           0 :       return OTS_FAILURE_MSG("Non default offset too high (%d >= %ld) in record %d", records[i].non_default_offset, length, i);
     456             :     }
     457             :   }
     458             : 
     459           0 :   for (unsigned i = 0; i < num_records; ++i) {
     460             :     // Checks default UVS table
     461           0 :     if (records[i].default_offset) {
     462           0 :       subtable.set_offset(records[i].default_offset);
     463           0 :       uint32_t num_ranges = 0;
     464           0 :       if (!subtable.ReadU32(&num_ranges)) {
     465           0 :         return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i);
     466             :       }
     467           0 :       if (num_ranges == 0 || subtable.remaining() / 4 < num_ranges) {
     468           0 :         return OTS_FAILURE_MSG("Bad number of ranges (%d) in record %d", num_ranges, i);
     469             :       }
     470             : 
     471           0 :       uint32_t last_unicode_value = 0;
     472             :       std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges
     473           0 :           = records[i].ranges;
     474           0 :       ranges.resize(num_ranges);
     475             : 
     476           0 :       for (unsigned j = 0; j < num_ranges; ++j) {
     477           0 :         if (!subtable.ReadU24(&ranges[j].unicode_value) ||
     478           0 :             !subtable.ReadU8(&ranges[j].additional_count)) {
     479           0 :           return OTS_FAILURE_MSG("Can't read range info in variation selector record %d", i);
     480             :         }
     481             :         const uint32_t check_value =
     482           0 :             ranges[j].unicode_value + ranges[j].additional_count;
     483           0 :         if (ranges[j].unicode_value == 0 ||
     484           0 :             ranges[j].unicode_value > kUnicodeUpperLimit ||
     485           0 :             check_value > kUVSUpperLimit ||
     486           0 :             (last_unicode_value &&
     487           0 :              ranges[j].unicode_value <= last_unicode_value)) {
     488           0 :           return OTS_FAILURE_MSG("Bad Unicode value *%04X) in variation selector range %d record %d", ranges[j].unicode_value, j, i);
     489             :         }
     490           0 :         last_unicode_value = check_value;
     491             :       }
     492             :     }
     493             : 
     494             :     // Checks non default UVS table
     495           0 :     if (records[i].non_default_offset) {
     496           0 :       subtable.set_offset(records[i].non_default_offset);
     497           0 :       uint32_t num_mappings = 0;
     498           0 :       if (!subtable.ReadU32(&num_mappings)) {
     499           0 :         return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i);
     500             :       }
     501           0 :       if (num_mappings == 0 || subtable.remaining() / 5 < num_mappings) {
     502           0 :         return OTS_FAILURE_MSG("Bad number of mappings (%d) in variation selector record %d", num_mappings, i);
     503             :       }
     504             : 
     505           0 :       uint32_t last_unicode_value = 0;
     506             :       std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings
     507           0 :           = records[i].mappings;
     508           0 :       mappings.resize(num_mappings);
     509             : 
     510           0 :       for (unsigned j = 0; j < num_mappings; ++j) {
     511           0 :         if (!subtable.ReadU24(&mappings[j].unicode_value) ||
     512           0 :             !subtable.ReadU16(&mappings[j].glyph_id)) {
     513           0 :           return OTS_FAILURE_MSG("Can't read mapping %d in variation selector record %d", j, i);
     514             :         }
     515           0 :         if (mappings[j].glyph_id == 0 ||
     516           0 :             mappings[j].unicode_value == 0 ||
     517           0 :             mappings[j].unicode_value > kUnicodeUpperLimit ||
     518           0 :             (last_unicode_value &&
     519           0 :              mappings[j].unicode_value <= last_unicode_value)) {
     520           0 :           return OTS_FAILURE_MSG("Bad mapping (%04X -> %d) in mapping %d of variation selector %d", mappings[j].unicode_value, mappings[j].glyph_id, j, i);
     521             :         }
     522           0 :         last_unicode_value = mappings[j].unicode_value;
     523             :       }
     524             :     }
     525             :   }
     526             : 
     527           0 :   if (subtable.offset() != length) {
     528           0 :     return OTS_FAILURE_MSG("Bad subtable offset (%ld != %ld)", subtable.offset(), length);
     529             :   }
     530           0 :   font->cmap->subtable_0_5_14_length = subtable.offset();
     531           0 :   return true;
     532             : }
     533             : 
     534           0 : bool Parse100(ots::Font *font, const uint8_t *data, size_t length) {
     535             :   // Mac Roman table
     536           0 :   ots::Buffer subtable(data, length);
     537             : 
     538           0 :   if (!subtable.Skip(4)) {
     539           0 :     return OTS_FAILURE_MSG("Bad cmap subtable");
     540             :   }
     541           0 :   uint16_t language = 0;
     542           0 :   if (!subtable.ReadU16(&language)) {
     543           0 :     return OTS_FAILURE_MSG("Can't read language in cmap subtable");
     544             :   }
     545           0 :   if (language) {
     546             :     // simsun.ttf has non-zero language id.
     547           0 :     OTS_WARNING("language id should be zero: %u", language);
     548             :   }
     549             : 
     550           0 :   font->cmap->subtable_1_0_0.reserve(kFormat0ArraySize);
     551           0 :   for (size_t i = 0; i < kFormat0ArraySize; ++i) {
     552           0 :     uint8_t glyph_id = 0;
     553           0 :     if (!subtable.ReadU8(&glyph_id)) {
     554           0 :       return OTS_FAILURE_MSG("Can't read glyph id at array[%ld] in cmap subtable", i);
     555             :     }
     556           0 :     font->cmap->subtable_1_0_0.push_back(glyph_id);
     557             :   }
     558             : 
     559           0 :   return true;
     560             : }
     561             : 
     562             : }  // namespace
     563             : 
     564             : namespace ots {
     565             : 
     566           0 : bool ots_cmap_parse(Font *font, const uint8_t *data, size_t length) {
     567           0 :   Buffer table(data, length);
     568           0 :   font->cmap = new OpenTypeCMAP;
     569             : 
     570           0 :   uint16_t version = 0;
     571           0 :   uint16_t num_tables = 0;
     572           0 :   if (!table.ReadU16(&version) ||
     573           0 :       !table.ReadU16(&num_tables)) {
     574           0 :     return OTS_FAILURE_MSG("Can't read structure of cmap");
     575             :   }
     576             : 
     577           0 :   if (version != 0) {
     578           0 :     return OTS_FAILURE_MSG("Non zero cmap version (%d)", version);
     579             :   }
     580           0 :   if (!num_tables) {
     581           0 :     return OTS_FAILURE_MSG("No subtables in cmap!");
     582             :   }
     583             : 
     584           0 :   std::vector<CMAPSubtableHeader> subtable_headers;
     585             : 
     586             :   // read the subtable headers
     587           0 :   subtable_headers.reserve(num_tables);
     588           0 :   for (unsigned i = 0; i < num_tables; ++i) {
     589             :     CMAPSubtableHeader subt;
     590             : 
     591           0 :     if (!table.ReadU16(&subt.platform) ||
     592           0 :         !table.ReadU16(&subt.encoding) ||
     593           0 :         !table.ReadU32(&subt.offset)) {
     594           0 :       return OTS_FAILURE_MSG("Can't read subtable information cmap subtable %d", i);
     595             :     }
     596             : 
     597           0 :     subtable_headers.push_back(subt);
     598             :   }
     599             : 
     600           0 :   const size_t data_offset = table.offset();
     601             : 
     602             :   // make sure that all the offsets are valid.
     603           0 :   for (unsigned i = 0; i < num_tables; ++i) {
     604           0 :     if (subtable_headers[i].offset > 1024 * 1024 * 1024) {
     605           0 :       return OTS_FAILURE_MSG("Bad subtable offset in cmap subtable %d", i);
     606             :     }
     607           0 :     if (subtable_headers[i].offset < data_offset ||
     608           0 :         subtable_headers[i].offset >= length) {
     609           0 :       return OTS_FAILURE_MSG("Bad subtable offset (%d) in cmap subtable %d", subtable_headers[i].offset, i);
     610             :     }
     611             :   }
     612             : 
     613             :   // the format of the table is the first couple of bytes in the table. The
     614             :   // length of the table is stored in a format-specific way.
     615           0 :   for (unsigned i = 0; i < num_tables; ++i) {
     616           0 :     table.set_offset(subtable_headers[i].offset);
     617           0 :     if (!table.ReadU16(&subtable_headers[i].format)) {
     618           0 :       return OTS_FAILURE_MSG("Can't read cmap subtable header format %d", i);
     619             :     }
     620             : 
     621           0 :     uint16_t len = 0;
     622           0 :     uint16_t lang = 0;
     623           0 :     switch (subtable_headers[i].format) {
     624             :       case 0:
     625             :       case 4:
     626           0 :         if (!table.ReadU16(&len)) {
     627           0 :           return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i);
     628             :         }
     629           0 :         if (!table.ReadU16(&lang)) {
     630           0 :           return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i);
     631             :         }
     632           0 :         subtable_headers[i].length = len;
     633           0 :         subtable_headers[i].language = lang;
     634           0 :         break;
     635             :       case 12:
     636             :       case 13:
     637           0 :         if (!table.Skip(2)) {
     638           0 :           return OTS_FAILURE_MSG("Bad cmap subtable %d structure", i);
     639             :         }
     640           0 :         if (!table.ReadU32(&subtable_headers[i].length)) {
     641           0 :           return OTS_FAILURE_MSG("Can read cmap subtable %d length", i);
     642             :         }
     643           0 :         if (!table.ReadU32(&subtable_headers[i].language)) {
     644           0 :           return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i);
     645             :         }
     646           0 :         break;
     647             :       case 14:
     648           0 :         if (!table.ReadU32(&subtable_headers[i].length)) {
     649           0 :           return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i);
     650             :         }
     651           0 :         subtable_headers[i].language = 0;
     652           0 :         break;
     653             :       default:
     654           0 :         subtable_headers[i].length = 0;
     655           0 :         subtable_headers[i].language = 0;
     656           0 :         break;
     657             :     }
     658             :   }
     659             : 
     660             :   // check if the table is sorted first by platform ID, then by encoding ID.
     661           0 :   for (unsigned i = 1; i < num_tables; ++i) {
     662           0 :     if (subtable_headers[i - 1].platform > subtable_headers[i].platform ||
     663           0 :         (subtable_headers[i - 1].platform == subtable_headers[i].platform &&
     664           0 :          (subtable_headers[i - 1].encoding > subtable_headers[i].encoding ||
     665           0 :           (subtable_headers[i - 1].encoding == subtable_headers[i].encoding &&
     666           0 :            subtable_headers[i - 1].language > subtable_headers[i].language))))
     667           0 :       OTS_WARNING("subtable %d with platform ID %d, encoding ID %d, language ID %d "
     668             :                   "following subtable with platform ID %d, encoding ID %d, language ID %d",
     669             :                   i,
     670             :                   subtable_headers[i].platform,
     671             :                   subtable_headers[i].encoding,
     672             :                   subtable_headers[i].language,
     673             :                   subtable_headers[i - 1].platform,
     674             :                   subtable_headers[i - 1].encoding,
     675           0 :                   subtable_headers[i - 1].language);
     676             :   }
     677             : 
     678             :   // Now, verify that all the lengths are sane
     679           0 :   for (unsigned i = 0; i < num_tables; ++i) {
     680           0 :     if (!subtable_headers[i].length) continue;
     681           0 :     if (subtable_headers[i].length > 1024 * 1024 * 1024) {
     682           0 :       return OTS_FAILURE_MSG("Bad cmap subtable %d length", i);
     683             :     }
     684             :     // We know that both the offset and length are < 1GB, so the following
     685             :     // addition doesn't overflow
     686             :     const uint32_t end_byte
     687           0 :         = subtable_headers[i].offset + subtable_headers[i].length;
     688           0 :     if (end_byte > length) {
     689           0 :       return OTS_FAILURE_MSG("Over long cmap subtable %d @ %d for %d", i, subtable_headers[i].offset, subtable_headers[i].length);
     690             :     }
     691             :   }
     692             : 
     693             :   // check that the cmap subtables are not overlapping.
     694           0 :   std::set<std::pair<uint32_t, uint32_t> > uniq_checker;
     695           0 :   std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
     696           0 :   for (unsigned i = 0; i < num_tables; ++i) {
     697             :     const uint32_t end_byte
     698           0 :         = subtable_headers[i].offset + subtable_headers[i].length;
     699             : 
     700           0 :     if (!uniq_checker.insert(std::make_pair(subtable_headers[i].offset,
     701           0 :                                             end_byte)).second) {
     702             :       // Sometimes Unicode table and MS table share exactly the same data.
     703             :       // We'll allow this.
     704           0 :       continue;
     705             :     }
     706             :     overlap_checker.push_back(
     707           0 :         std::make_pair(subtable_headers[i].offset,
     708           0 :                        static_cast<uint8_t>(1) /* start */));
     709             :     overlap_checker.push_back(
     710           0 :         std::make_pair(end_byte, static_cast<uint8_t>(0) /* end */));
     711             :   }
     712           0 :   std::sort(overlap_checker.begin(), overlap_checker.end());
     713           0 :   int overlap_count = 0;
     714           0 :   for (unsigned i = 0; i < overlap_checker.size(); ++i) {
     715           0 :     overlap_count += (overlap_checker[i].second ? 1 : -1);
     716           0 :     if (overlap_count > 1) {
     717           0 :       return OTS_FAILURE_MSG("Excessive overlap count %d", overlap_count);
     718             :     }
     719             :   }
     720             : 
     721             :   // we grab the number of glyphs in the file from the maxp table to make sure
     722             :   // that the character map isn't referencing anything beyound this range.
     723           0 :   if (!font->maxp) {
     724           0 :     return OTS_FAILURE_MSG("No maxp table in font! Needed by cmap.");
     725             :   }
     726           0 :   const uint16_t num_glyphs = font->maxp->num_glyphs;
     727             : 
     728             :   // We only support a subset of the possible character map tables. Microsoft
     729             :   // 'strongly recommends' that everyone supports the Unicode BMP table with
     730             :   // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables:
     731             :   //   Platform ID   Encoding ID  Format
     732             :   //   0             0            4       (Unicode Default)
     733             :   //   0             1            4       (Unicode 1.1)
     734             :   //   0             3            4       (Unicode BMP)
     735             :   //   0             3            12      (Unicode UCS-4)
     736             :   //   0             5            14      (Unicode Variation Sequences)
     737             :   //   1             0            0       (Mac Roman)
     738             :   //   3             0            4       (MS Symbol)
     739             :   //   3             1            4       (MS Unicode BMP)
     740             :   //   3             10           12      (MS Unicode UCS-4)
     741             :   //   3             10           13      (MS UCS-4 Fallback mapping)
     742             :   //
     743             :   // Note:
     744             :   //  * 0-0-4 and 0-1-4 tables are (usually) written as a 3-1-4 table. If 3-1-4 table
     745             :   //    also exists, the 0-0-4 or 0-1-4 tables are ignored.
     746             :   //  * Unlike 0-0-4 table, 0-3-4 table is written as a 0-3-4 table.
     747             :   //    Some fonts which include 0-5-14 table seems to be required 0-3-4
     748             :   //    table. The 0-3-4 table will be wriiten even if 3-1-4 table also exists.
     749             :   //  * 0-3-12 table is written as a 3-10-12 table. If 3-10-12 table also
     750             :   //    exists, the 0-3-12 table is ignored.
     751             :   //
     752             : 
     753           0 :   for (unsigned i = 0; i < num_tables; ++i) {
     754           0 :     if (subtable_headers[i].platform == 0) {
     755             :       // Unicode platform
     756             : 
     757           0 :       if ((subtable_headers[i].encoding == 0 || subtable_headers[i].encoding == 1) &&
     758           0 :           (subtable_headers[i].format == 4)) {
     759             :         // parse and output the 0-0-4 and 0-1-4 tables as 3-1-4 table. Sometimes the 0-0-4
     760             :         // table actually points to MS symbol data and thus should be parsed as
     761             :         // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be
     762             :         // recovered in ots_cmap_serialise().
     763           0 :         if (!ParseFormat4(font, 3, 1, data + subtable_headers[i].offset,
     764           0 :                       subtable_headers[i].length, num_glyphs)) {
     765           0 :           return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
     766             :         }
     767           0 :       } else if ((subtable_headers[i].encoding == 3) &&
     768           0 :                  (subtable_headers[i].format == 4)) {
     769             :         // parse and output the 0-3-4 table as 0-3-4 table.
     770           0 :         if (!ParseFormat4(font, 0, 3, data + subtable_headers[i].offset,
     771           0 :                       subtable_headers[i].length, num_glyphs)) {
     772           0 :           return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
     773             :         }
     774           0 :       } else if ((subtable_headers[i].encoding == 3) &&
     775           0 :                  (subtable_headers[i].format == 12)) {
     776             :         // parse and output the 0-3-12 table as 3-10-12 table.
     777           0 :         if (!Parse31012(font, data + subtable_headers[i].offset,
     778           0 :                         subtable_headers[i].length, num_glyphs)) {
     779           0 :           return OTS_FAILURE_MSG("Failed to parse format 12 cmap subtable %d", i);
     780             :         }
     781           0 :       } else if ((subtable_headers[i].encoding == 5) &&
     782           0 :                  (subtable_headers[i].format == 14)) {
     783           0 :         if (!Parse0514(font, data + subtable_headers[i].offset,
     784           0 :                        subtable_headers[i].length, num_glyphs)) {
     785           0 :           return OTS_FAILURE_MSG("Failed to parse format 14 cmap subtable %d", i);
     786             :         }
     787             :       }
     788           0 :     } else if (subtable_headers[i].platform == 1) {
     789             :       // Mac platform
     790             : 
     791           0 :       if ((subtable_headers[i].encoding == 0) &&
     792           0 :           (subtable_headers[i].format == 0)) {
     793             :         // parse and output the 1-0-0 table.
     794           0 :         if (!Parse100(font, data + subtable_headers[i].offset,
     795           0 :                       subtable_headers[i].length)) {
     796           0 :           return OTS_FAILURE();
     797             :         }
     798             :       }
     799           0 :     } else if (subtable_headers[i].platform == 3) {
     800             :       // MS platform
     801             : 
     802           0 :       switch (subtable_headers[i].encoding) {
     803             :         case 0:
     804             :         case 1:
     805           0 :           if (subtable_headers[i].format == 4) {
     806             :             // parse 3-0-4 or 3-1-4 table.
     807           0 :             if (!ParseFormat4(font, subtable_headers[i].platform,
     808           0 :                           subtable_headers[i].encoding,
     809           0 :                           data + subtable_headers[i].offset,
     810           0 :                           subtable_headers[i].length, num_glyphs)) {
     811           0 :               return OTS_FAILURE();
     812             :             }
     813             :           }
     814           0 :           break;
     815             :         case 10:
     816           0 :           if (subtable_headers[i].format == 12) {
     817           0 :             font->cmap->subtable_3_10_12.clear();
     818           0 :             if (!Parse31012(font, data + subtable_headers[i].offset,
     819           0 :                             subtable_headers[i].length, num_glyphs)) {
     820           0 :               return OTS_FAILURE();
     821             :             }
     822           0 :           } else if (subtable_headers[i].format == 13) {
     823           0 :             font->cmap->subtable_3_10_13.clear();
     824           0 :             if (!Parse31013(font, data + subtable_headers[i].offset,
     825           0 :                             subtable_headers[i].length, num_glyphs)) {
     826           0 :               return OTS_FAILURE();
     827             :             }
     828             :           }
     829           0 :           break;
     830             :       }
     831             :     }
     832             :   }
     833             : 
     834           0 :   return true;
     835             : }
     836             : 
     837           0 : bool ots_cmap_should_serialise(Font *font) {
     838           0 :   return font->cmap != NULL;
     839             : }
     840             : 
     841           0 : bool ots_cmap_serialise(OTSStream *out, Font *font) {
     842           0 :   const bool have_034 = font->cmap->subtable_0_3_4_data != NULL;
     843           0 :   const bool have_0514 = font->cmap->subtable_0_5_14.size() != 0;
     844           0 :   const bool have_100 = font->cmap->subtable_1_0_0.size() != 0;
     845           0 :   const bool have_304 = font->cmap->subtable_3_0_4_data != NULL;
     846             :   // MS Symbol and MS Unicode tables should not co-exist.
     847             :   // See the comment above in 0-0-4 parser.
     848           0 :   const bool have_314 = (!have_304) && font->cmap->subtable_3_1_4_data;
     849           0 :   const bool have_31012 = font->cmap->subtable_3_10_12.size() != 0;
     850           0 :   const bool have_31013 = font->cmap->subtable_3_10_13.size() != 0;
     851           0 :   const uint16_t num_subtables = static_cast<uint16_t>(have_034) +
     852           0 :                                  static_cast<uint16_t>(have_0514) +
     853           0 :                                  static_cast<uint16_t>(have_100) +
     854           0 :                                  static_cast<uint16_t>(have_304) +
     855           0 :                                  static_cast<uint16_t>(have_314) +
     856           0 :                                  static_cast<uint16_t>(have_31012) +
     857           0 :                                  static_cast<uint16_t>(have_31013);
     858           0 :   const off_t table_start = out->Tell();
     859             : 
     860             :   // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables
     861             :   // (e.g., old fonts for Mac). We don't support them.
     862           0 :   if (!have_304 && !have_314 && !have_034 && !have_31012 && !have_31013) {
     863           0 :     return OTS_FAILURE_MSG("no supported subtables were found");
     864             :   }
     865             : 
     866           0 :   if (!out->WriteU16(0) ||
     867           0 :       !out->WriteU16(num_subtables)) {
     868           0 :     return OTS_FAILURE();
     869             :   }
     870             : 
     871           0 :   const off_t record_offset = out->Tell();
     872           0 :   if (!out->Pad(num_subtables * 8)) {
     873           0 :     return OTS_FAILURE();
     874             :   }
     875             : 
     876           0 :   const off_t offset_034 = out->Tell();
     877           0 :   if (have_034) {
     878           0 :     if (!out->Write(font->cmap->subtable_0_3_4_data,
     879           0 :                     font->cmap->subtable_0_3_4_length)) {
     880           0 :       return OTS_FAILURE();
     881             :     }
     882             :   }
     883             : 
     884           0 :   const off_t offset_0514 = out->Tell();
     885           0 :   if (have_0514) {
     886             :     const std::vector<ots::OpenTypeCMAPSubtableVSRecord> &records
     887           0 :         = font->cmap->subtable_0_5_14;
     888           0 :     const unsigned num_records = records.size();
     889           0 :     if (!out->WriteU16(14) ||
     890           0 :         !out->WriteU32(font->cmap->subtable_0_5_14_length) ||
     891           0 :         !out->WriteU32(num_records)) {
     892           0 :       return OTS_FAILURE();
     893             :     }
     894           0 :     for (unsigned i = 0; i < num_records; ++i) {
     895           0 :       if (!out->WriteU24(records[i].var_selector) ||
     896           0 :           !out->WriteU32(records[i].default_offset) ||
     897           0 :           !out->WriteU32(records[i].non_default_offset)) {
     898           0 :         return OTS_FAILURE();
     899             :       }
     900             :     }
     901           0 :     for (unsigned i = 0; i < num_records; ++i) {
     902           0 :       if (records[i].default_offset) {
     903             :         const std::vector<ots::OpenTypeCMAPSubtableVSRange> &ranges
     904           0 :             = records[i].ranges;
     905           0 :         const unsigned num_ranges = ranges.size();
     906           0 :         if (!out->Seek(records[i].default_offset + offset_0514) ||
     907           0 :             !out->WriteU32(num_ranges)) {
     908           0 :           return OTS_FAILURE();
     909             :         }
     910           0 :         for (unsigned j = 0; j < num_ranges; ++j) {
     911           0 :           if (!out->WriteU24(ranges[j].unicode_value) ||
     912           0 :               !out->WriteU8(ranges[j].additional_count)) {
     913           0 :             return OTS_FAILURE();
     914             :           }
     915             :         }
     916             :       }
     917           0 :       if (records[i].non_default_offset) {
     918             :         const std::vector<ots::OpenTypeCMAPSubtableVSMapping> &mappings
     919           0 :             = records[i].mappings;
     920           0 :         const unsigned num_mappings = mappings.size();
     921           0 :         if (!out->Seek(records[i].non_default_offset + offset_0514) ||
     922           0 :             !out->WriteU32(num_mappings)) {
     923           0 :           return OTS_FAILURE();
     924             :         }
     925           0 :         for (unsigned j = 0; j < num_mappings; ++j) {
     926           0 :           if (!out->WriteU24(mappings[j].unicode_value) ||
     927           0 :               !out->WriteU16(mappings[j].glyph_id)) {
     928           0 :             return OTS_FAILURE();
     929             :           }
     930             :         }
     931             :       }
     932             :     }
     933             :   }
     934             : 
     935           0 :   const off_t offset_100 = out->Tell();
     936           0 :   if (have_100) {
     937           0 :     if (!out->WriteU16(0) ||  // format
     938           0 :         !out->WriteU16(6 + kFormat0ArraySize) ||  // length
     939           0 :         !out->WriteU16(0)) {  // language
     940           0 :       return OTS_FAILURE();
     941             :     }
     942           0 :     if (!out->Write(&(font->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) {
     943           0 :       return OTS_FAILURE();
     944             :     }
     945             :   }
     946             : 
     947           0 :   const off_t offset_304 = out->Tell();
     948           0 :   if (have_304) {
     949           0 :     if (!out->Write(font->cmap->subtable_3_0_4_data,
     950           0 :                     font->cmap->subtable_3_0_4_length)) {
     951           0 :       return OTS_FAILURE();
     952             :     }
     953             :   }
     954             : 
     955           0 :   const off_t offset_314 = out->Tell();
     956           0 :   if (have_314) {
     957           0 :     if (!out->Write(font->cmap->subtable_3_1_4_data,
     958           0 :                     font->cmap->subtable_3_1_4_length)) {
     959           0 :       return OTS_FAILURE();
     960             :     }
     961             :   }
     962             : 
     963           0 :   const off_t offset_31012 = out->Tell();
     964           0 :   if (have_31012) {
     965             :     std::vector<OpenTypeCMAPSubtableRange> &groups
     966           0 :         = font->cmap->subtable_3_10_12;
     967           0 :     const unsigned num_groups = groups.size();
     968           0 :     if (!out->WriteU16(12) ||
     969           0 :         !out->WriteU16(0) ||
     970           0 :         !out->WriteU32(num_groups * 12 + 16) ||
     971           0 :         !out->WriteU32(0) ||
     972           0 :         !out->WriteU32(num_groups)) {
     973           0 :       return OTS_FAILURE();
     974             :     }
     975             : 
     976           0 :     for (unsigned i = 0; i < num_groups; ++i) {
     977           0 :       if (!out->WriteU32(groups[i].start_range) ||
     978           0 :           !out->WriteU32(groups[i].end_range) ||
     979           0 :           !out->WriteU32(groups[i].start_glyph_id)) {
     980           0 :         return OTS_FAILURE();
     981             :       }
     982             :     }
     983             :   }
     984             : 
     985           0 :   const off_t offset_31013 = out->Tell();
     986           0 :   if (have_31013) {
     987             :     std::vector<OpenTypeCMAPSubtableRange> &groups
     988           0 :         = font->cmap->subtable_3_10_13;
     989           0 :     const unsigned num_groups = groups.size();
     990           0 :     if (!out->WriteU16(13) ||
     991           0 :         !out->WriteU16(0) ||
     992           0 :         !out->WriteU32(num_groups * 12 + 16) ||
     993           0 :         !out->WriteU32(0) ||
     994           0 :         !out->WriteU32(num_groups)) {
     995           0 :       return OTS_FAILURE();
     996             :     }
     997             : 
     998           0 :     for (unsigned i = 0; i < num_groups; ++i) {
     999           0 :       if (!out->WriteU32(groups[i].start_range) ||
    1000           0 :           !out->WriteU32(groups[i].end_range) ||
    1001           0 :           !out->WriteU32(groups[i].start_glyph_id)) {
    1002           0 :         return OTS_FAILURE();
    1003             :       }
    1004             :     }
    1005             :   }
    1006             : 
    1007           0 :   const off_t table_end = out->Tell();
    1008             : 
    1009             :   // Now seek back and write the table of offsets
    1010           0 :   if (!out->Seek(record_offset)) {
    1011           0 :     return OTS_FAILURE();
    1012             :   }
    1013             : 
    1014           0 :   if (have_034) {
    1015           0 :     if (!out->WriteU16(0) ||
    1016           0 :         !out->WriteU16(3) ||
    1017           0 :         !out->WriteU32(offset_034 - table_start)) {
    1018           0 :       return OTS_FAILURE();
    1019             :     }
    1020             :   }
    1021             : 
    1022           0 :   if (have_0514) {
    1023           0 :     if (!out->WriteU16(0) ||
    1024           0 :         !out->WriteU16(5) ||
    1025           0 :         !out->WriteU32(offset_0514 - table_start)) {
    1026           0 :       return OTS_FAILURE();
    1027             :     }
    1028             :   }
    1029             : 
    1030           0 :   if (have_100) {
    1031           0 :     if (!out->WriteU16(1) ||
    1032           0 :         !out->WriteU16(0) ||
    1033           0 :         !out->WriteU32(offset_100 - table_start)) {
    1034           0 :       return OTS_FAILURE();
    1035             :     }
    1036             :   }
    1037             : 
    1038           0 :   if (have_304) {
    1039           0 :     if (!out->WriteU16(3) ||
    1040           0 :         !out->WriteU16(0) ||
    1041           0 :         !out->WriteU32(offset_304 - table_start)) {
    1042           0 :       return OTS_FAILURE();
    1043             :     }
    1044             :   }
    1045             : 
    1046           0 :   if (have_314) {
    1047           0 :     if (!out->WriteU16(3) ||
    1048           0 :         !out->WriteU16(1) ||
    1049           0 :         !out->WriteU32(offset_314 - table_start)) {
    1050           0 :       return OTS_FAILURE();
    1051             :     }
    1052             :   }
    1053             : 
    1054           0 :   if (have_31012) {
    1055           0 :     if (!out->WriteU16(3) ||
    1056           0 :         !out->WriteU16(10) ||
    1057           0 :         !out->WriteU32(offset_31012 - table_start)) {
    1058           0 :       return OTS_FAILURE();
    1059             :     }
    1060             :   }
    1061             : 
    1062           0 :   if (have_31013) {
    1063           0 :     if (!out->WriteU16(3) ||
    1064           0 :         !out->WriteU16(10) ||
    1065           0 :         !out->WriteU32(offset_31013 - table_start)) {
    1066           0 :       return OTS_FAILURE();
    1067             :     }
    1068             :   }
    1069             : 
    1070           0 :   if (!out->Seek(table_end)) {
    1071           0 :     return OTS_FAILURE();
    1072             :   }
    1073             : 
    1074           0 :   return true;
    1075             : }
    1076             : 
    1077           0 : void ots_cmap_reuse(Font *font, Font *other) {
    1078           0 :   font->cmap = other->cmap;
    1079           0 :   font->cmap_reused = true;
    1080           0 : }
    1081             : 
    1082           0 : void ots_cmap_free(Font *font) {
    1083           0 :   delete font->cmap;
    1084           0 : }
    1085             : 
    1086             : }  // namespace ots
    1087             : 
    1088             : #undef TABLE_NAME

Generated by: LCOV version 1.13