LCOV - app.info - gfx/ots/src/cmap.cc

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

Generated by: LCOV version 1.7