1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/ots/src/cmap.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1103 @@ 1.4 +// Copyright (c) 2009 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "cmap.h" 1.9 + 1.10 +#include <algorithm> 1.11 +#include <set> 1.12 +#include <utility> 1.13 +#include <vector> 1.14 + 1.15 +#include "maxp.h" 1.16 +#include "os2.h" 1.17 + 1.18 +// cmap - Character To Glyph Index Mapping Table 1.19 +// http://www.microsoft.com/typography/otspec/cmap.htm 1.20 + 1.21 +#define TABLE_NAME "cmap" 1.22 + 1.23 +namespace { 1.24 + 1.25 +struct CMAPSubtableHeader { 1.26 + uint16_t platform; 1.27 + uint16_t encoding; 1.28 + uint32_t offset; 1.29 + uint16_t format; 1.30 + uint32_t length; 1.31 + uint32_t language; 1.32 +}; 1.33 + 1.34 +struct Subtable314Range { 1.35 + uint16_t start_range; 1.36 + uint16_t end_range; 1.37 + int16_t id_delta; 1.38 + uint16_t id_range_offset; 1.39 + uint32_t id_range_offset_offset; 1.40 +}; 1.41 + 1.42 +// The maximum number of groups in format 12, 13 or 14 subtables. 1.43 +// Note: 0xFFFF is the maximum number of glyphs in a single font file. 1.44 +const unsigned kMaxCMAPGroups = 0xFFFF; 1.45 + 1.46 +// Glyph array size for the Mac Roman (format 0) table. 1.47 +const size_t kFormat0ArraySize = 256; 1.48 + 1.49 +// The upper limit of the Unicode code point. 1.50 +const uint32_t kUnicodeUpperLimit = 0x10FFFF; 1.51 + 1.52 +// The maximum number of UVS records (See below). 1.53 +const uint32_t kMaxCMAPSelectorRecords = 259; 1.54 +// The range of UVSes are: 1.55 +// 0x180B-0x180D (3 code points) 1.56 +// 0xFE00-0xFE0F (16 code points) 1.57 +// 0xE0100-0xE01EF (240 code points) 1.58 +const uint32_t kMongolianVSStart = 0x180B; 1.59 +const uint32_t kMongolianVSEnd = 0x180D; 1.60 +const uint32_t kVSStart = 0xFE00; 1.61 +const uint32_t kVSEnd = 0xFE0F; 1.62 +const uint32_t kIVSStart = 0xE0100; 1.63 +const uint32_t kIVSEnd = 0xE01EF; 1.64 +const uint32_t kUVSUpperLimit = 0xFFFFFF; 1.65 + 1.66 +// Parses Format 4 tables 1.67 +bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding, 1.68 + const uint8_t *data, size_t length, uint16_t num_glyphs) { 1.69 + ots::Buffer subtable(data, length); 1.70 + 1.71 + // 0.3.4, 3.0.4 or 3.1.4 subtables are complex and, rather than expanding the 1.72 + // whole thing and recompacting it, we validate it and include it verbatim 1.73 + // in the output. 1.74 + 1.75 + if (!file->os2) { 1.76 + return OTS_FAILURE_MSG("Required OS/2 table missing"); 1.77 + } 1.78 + 1.79 + if (!subtable.Skip(4)) { 1.80 + return OTS_FAILURE_MSG("Can't read 4 bytes at start of cmap format 4 subtable"); 1.81 + } 1.82 + uint16_t language = 0; 1.83 + if (!subtable.ReadU16(&language)) { 1.84 + return OTS_FAILURE_MSG("Can't read language"); 1.85 + } 1.86 + if (language) { 1.87 + // Platform ID 3 (windows) subtables should have language '0'. 1.88 + return OTS_FAILURE_MSG("Languages should be 0 (%d)", language); 1.89 + } 1.90 + 1.91 + uint16_t segcountx2, search_range, entry_selector, range_shift; 1.92 + segcountx2 = search_range = entry_selector = range_shift = 0; 1.93 + if (!subtable.ReadU16(&segcountx2) || 1.94 + !subtable.ReadU16(&search_range) || 1.95 + !subtable.ReadU16(&entry_selector) || 1.96 + !subtable.ReadU16(&range_shift)) { 1.97 + return OTS_FAILURE_MSG("Failed to read subcmap structure"); 1.98 + } 1.99 + 1.100 + if (segcountx2 & 1 || search_range & 1) { 1.101 + return OTS_FAILURE_MSG("Bad subcmap structure"); 1.102 + } 1.103 + const uint16_t segcount = segcountx2 >> 1; 1.104 + // There must be at least one segment according the spec. 1.105 + if (segcount < 1) { 1.106 + return OTS_FAILURE_MSG("Segcount < 1 (%d)", segcount); 1.107 + } 1.108 + 1.109 + // log2segcount is the maximal x s.t. 2^x < segcount 1.110 + unsigned log2segcount = 0; 1.111 + while (1u << (log2segcount + 1) <= segcount) { 1.112 + log2segcount++; 1.113 + } 1.114 + 1.115 + const uint16_t expected_search_range = 2 * 1u << log2segcount; 1.116 + if (expected_search_range != search_range) { 1.117 + return OTS_FAILURE_MSG("expected search range != search range (%d != %d)", expected_search_range, search_range); 1.118 + } 1.119 + 1.120 + if (entry_selector != log2segcount) { 1.121 + return OTS_FAILURE_MSG("entry selector != log2(segement count) (%d != %d)", entry_selector, log2segcount); 1.122 + } 1.123 + 1.124 + const uint16_t expected_range_shift = segcountx2 - search_range; 1.125 + if (range_shift != expected_range_shift) { 1.126 + return OTS_FAILURE_MSG("unexpected range shift (%d != %d)", range_shift, expected_range_shift); 1.127 + } 1.128 + 1.129 + std::vector<Subtable314Range> ranges(segcount); 1.130 + 1.131 + for (unsigned i = 0; i < segcount; ++i) { 1.132 + if (!subtable.ReadU16(&ranges[i].end_range)) { 1.133 + return OTS_FAILURE_MSG("Failed to read segment %d", i); 1.134 + } 1.135 + } 1.136 + 1.137 + uint16_t padding; 1.138 + if (!subtable.ReadU16(&padding)) { 1.139 + return OTS_FAILURE_MSG("Failed to read cmap subtable segment padding"); 1.140 + } 1.141 + if (padding) { 1.142 + return OTS_FAILURE_MSG("Non zero cmap subtable segment padding (%d)", padding); 1.143 + } 1.144 + 1.145 + for (unsigned i = 0; i < segcount; ++i) { 1.146 + if (!subtable.ReadU16(&ranges[i].start_range)) { 1.147 + return OTS_FAILURE_MSG("Failed to read segment start range %d", i); 1.148 + } 1.149 + } 1.150 + for (unsigned i = 0; i < segcount; ++i) { 1.151 + if (!subtable.ReadS16(&ranges[i].id_delta)) { 1.152 + return OTS_FAILURE_MSG("Failed to read segment delta %d", i); 1.153 + } 1.154 + } 1.155 + for (unsigned i = 0; i < segcount; ++i) { 1.156 + ranges[i].id_range_offset_offset = subtable.offset(); 1.157 + if (!subtable.ReadU16(&ranges[i].id_range_offset)) { 1.158 + return OTS_FAILURE_MSG("Failed to read segment range offset %d", i); 1.159 + } 1.160 + 1.161 + if (ranges[i].id_range_offset & 1) { 1.162 + // Some font generators seem to put 65535 on id_range_offset 1.163 + // for 0xFFFF-0xFFFF range. 1.164 + // (e.g., many fonts in http://www.princexml.com/fonts/) 1.165 + if (i == segcount - 1u) { 1.166 + OTS_WARNING("bad id_range_offset"); 1.167 + ranges[i].id_range_offset = 0; 1.168 + // The id_range_offset value in the transcoded font will not change 1.169 + // since this table is not actually "transcoded" yet. 1.170 + } else { 1.171 + return OTS_FAILURE_MSG("Bad segment offset (%d)", ranges[i].id_range_offset); 1.172 + } 1.173 + } 1.174 + } 1.175 + 1.176 + // ranges must be ascending order, based on the end_code. Ranges may not 1.177 + // overlap. 1.178 + for (unsigned i = 1; i < segcount; ++i) { 1.179 + if ((i == segcount - 1u) && 1.180 + (ranges[i - 1].start_range == 0xffff) && 1.181 + (ranges[i - 1].end_range == 0xffff) && 1.182 + (ranges[i].start_range == 0xffff) && 1.183 + (ranges[i].end_range == 0xffff)) { 1.184 + // Some fonts (e.g., Germania.ttf) have multiple 0xffff terminators. 1.185 + // We'll accept them as an exception. 1.186 + OTS_WARNING("multiple 0xffff terminators found"); 1.187 + continue; 1.188 + } 1.189 + 1.190 + // Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have 1.191 + // unsorted table... 1.192 + if (ranges[i].end_range <= ranges[i - 1].end_range) { 1.193 + return OTS_FAILURE_MSG("Out of order end range (%d <= %d)", ranges[i].end_range, ranges[i-1].end_range); 1.194 + } 1.195 + if (ranges[i].start_range <= ranges[i - 1].end_range) { 1.196 + return OTS_FAILURE_MSG("out of order start range (%d <= %d)", ranges[i].start_range, ranges[i-1].end_range); 1.197 + } 1.198 + 1.199 + // On many fonts, the value of {first, last}_char_index are incorrect. 1.200 + // Fix them. 1.201 + if (file->os2->first_char_index != 0xFFFF && 1.202 + ranges[i].start_range != 0xFFFF && 1.203 + file->os2->first_char_index > ranges[i].start_range) { 1.204 + file->os2->first_char_index = ranges[i].start_range; 1.205 + } 1.206 + if (file->os2->last_char_index != 0xFFFF && 1.207 + ranges[i].end_range != 0xFFFF && 1.208 + file->os2->last_char_index < ranges[i].end_range) { 1.209 + file->os2->last_char_index = ranges[i].end_range; 1.210 + } 1.211 + } 1.212 + 1.213 + // The last range must end at 0xffff 1.214 + if (ranges[segcount - 1].start_range != 0xffff || ranges[segcount - 1].end_range != 0xffff) { 1.215 + return OTS_FAILURE_MSG("Final segment start and end must be 0xFFFF (0x%04X-0x%04X)", 1.216 + ranges[segcount - 1].start_range, ranges[segcount - 1].end_range); 1.217 + } 1.218 + 1.219 + // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of 1.220 + // each code-point defined in the table and make sure that they are all valid 1.221 + // glyphs and that we don't access anything out-of-bounds. 1.222 + for (unsigned i = 0; i < segcount; ++i) { 1.223 + for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) { 1.224 + const uint16_t code_point = cp; 1.225 + if (ranges[i].id_range_offset == 0) { 1.226 + // this is explictly allowed to overflow in the spec 1.227 + const uint16_t glyph = code_point + ranges[i].id_delta; 1.228 + if (glyph >= num_glyphs) { 1.229 + return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1); 1.230 + } 1.231 + } else { 1.232 + const uint16_t range_delta = code_point - ranges[i].start_range; 1.233 + // this might seem odd, but it's true. The offset is relative to the 1.234 + // location of the offset value itself. 1.235 + const uint32_t glyph_id_offset = ranges[i].id_range_offset_offset + 1.236 + ranges[i].id_range_offset + 1.237 + range_delta * 2; 1.238 + // We need to be able to access a 16-bit value from this offset 1.239 + if (glyph_id_offset + 1 >= length) { 1.240 + return OTS_FAILURE_MSG("bad glyph id offset (%d > %ld)", glyph_id_offset, length); 1.241 + } 1.242 + uint16_t glyph; 1.243 + std::memcpy(&glyph, data + glyph_id_offset, 2); 1.244 + glyph = ntohs(glyph); 1.245 + if (glyph >= num_glyphs) { 1.246 + return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1); 1.247 + } 1.248 + } 1.249 + } 1.250 + } 1.251 + 1.252 + // We accept the table. 1.253 + // TODO(yusukes): transcode the subtable. 1.254 + if (platform == 3 && encoding == 0) { 1.255 + file->cmap->subtable_3_0_4_data = data; 1.256 + file->cmap->subtable_3_0_4_length = length; 1.257 + } else if (platform == 3 && encoding == 1) { 1.258 + file->cmap->subtable_3_1_4_data = data; 1.259 + file->cmap->subtable_3_1_4_length = length; 1.260 + } else if (platform == 0 && encoding == 3) { 1.261 + file->cmap->subtable_0_3_4_data = data; 1.262 + file->cmap->subtable_0_3_4_length = length; 1.263 + } else { 1.264 + return OTS_FAILURE_MSG("Unknown cmap subtable type (platform=%d, encoding=%d)", platform, encoding); 1.265 + } 1.266 + 1.267 + return true; 1.268 +} 1.269 + 1.270 +bool Parse31012(ots::OpenTypeFile *file, 1.271 + const uint8_t *data, size_t length, uint16_t num_glyphs) { 1.272 + ots::Buffer subtable(data, length); 1.273 + 1.274 + // Format 12 tables are simple. We parse these and fully serialise them 1.275 + // later. 1.276 + 1.277 + if (!subtable.Skip(8)) { 1.278 + return OTS_FAILURE_MSG("failed to skip the first 8 bytes of format 12 subtable"); 1.279 + } 1.280 + uint32_t language = 0; 1.281 + if (!subtable.ReadU32(&language)) { 1.282 + return OTS_FAILURE_MSG("can't read format 12 subtable language"); 1.283 + } 1.284 + if (language) { 1.285 + return OTS_FAILURE_MSG("format 12 subtable language should be zero (%d)", language); 1.286 + } 1.287 + 1.288 + uint32_t num_groups = 0; 1.289 + if (!subtable.ReadU32(&num_groups)) { 1.290 + return OTS_FAILURE_MSG("can't read number of format 12 subtable groups"); 1.291 + } 1.292 + if (num_groups == 0 || num_groups > kMaxCMAPGroups) { 1.293 + return OTS_FAILURE_MSG("bad format 12 subtable group count %d", num_groups); 1.294 + } 1.295 + 1.296 + std::vector<ots::OpenTypeCMAPSubtableRange> &groups 1.297 + = file->cmap->subtable_3_10_12; 1.298 + groups.resize(num_groups); 1.299 + 1.300 + for (unsigned i = 0; i < num_groups; ++i) { 1.301 + if (!subtable.ReadU32(&groups[i].start_range) || 1.302 + !subtable.ReadU32(&groups[i].end_range) || 1.303 + !subtable.ReadU32(&groups[i].start_glyph_id)) { 1.304 + return OTS_FAILURE_MSG("can't read format 12 subtable group"); 1.305 + } 1.306 + 1.307 + if (groups[i].start_range > kUnicodeUpperLimit || 1.308 + groups[i].end_range > kUnicodeUpperLimit || 1.309 + groups[i].start_glyph_id > 0xFFFF) { 1.310 + return OTS_FAILURE_MSG("bad format 12 subtable group (startCharCode=0x%4X, endCharCode=0x%4X, startGlyphID=%d)", 1.311 + groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id); 1.312 + } 1.313 + 1.314 + // [0xD800, 0xDFFF] are surrogate code points. 1.315 + if (groups[i].start_range >= 0xD800 && 1.316 + groups[i].start_range <= 0xDFFF) { 1.317 + return OTS_FAILURE_MSG("format 12 subtable out of range group startCharCode (0x%4X)", groups[i].start_range); 1.318 + } 1.319 + if (groups[i].end_range >= 0xD800 && 1.320 + groups[i].end_range <= 0xDFFF) { 1.321 + return OTS_FAILURE_MSG("format 12 subtable out of range group endCharCode (0x%4X)", groups[i].end_range); 1.322 + } 1.323 + if (groups[i].start_range < 0xD800 && 1.324 + groups[i].end_range > 0xDFFF) { 1.325 + return OTS_FAILURE_MSG("bad format 12 subtable group startCharCode (0x%4X) or endCharCode (0x%4X)", 1.326 + groups[i].start_range, groups[i].end_range); 1.327 + } 1.328 + 1.329 + // We assert that the glyph value is within range. Because of the range 1.330 + // limits, above, we don't need to worry about overflow. 1.331 + if (groups[i].end_range < groups[i].start_range) { 1.332 + return OTS_FAILURE_MSG("format 12 subtable group endCharCode before startCharCode (0x%4X < 0x%4X)", 1.333 + groups[i].end_range, groups[i].start_range); 1.334 + } 1.335 + if ((groups[i].end_range - groups[i].start_range) + 1.336 + groups[i].start_glyph_id > num_glyphs) { 1.337 + return OTS_FAILURE_MSG("bad format 12 subtable group startGlyphID (%d)", groups[i].start_glyph_id); 1.338 + } 1.339 + } 1.340 + 1.341 + // the groups must be sorted by start code and may not overlap 1.342 + for (unsigned i = 1; i < num_groups; ++i) { 1.343 + if (groups[i].start_range <= groups[i - 1].start_range) { 1.344 + return OTS_FAILURE_MSG("out of order format 12 subtable group (startCharCode=0x%4X <= startCharCode=0x%4X of previous group)", 1.345 + groups[i].start_range, groups[i-1].start_range); 1.346 + } 1.347 + if (groups[i].start_range <= groups[i - 1].end_range) { 1.348 + return OTS_FAILURE_MSG("overlapping format 12 subtable groups (startCharCode=0x%4X <= endCharCode=0x%4X of previous group)", 1.349 + groups[i].start_range, groups[i-1].end_range); 1.350 + } 1.351 + } 1.352 + 1.353 + return true; 1.354 +} 1.355 + 1.356 +bool Parse31013(ots::OpenTypeFile *file, 1.357 + const uint8_t *data, size_t length, uint16_t num_glyphs) { 1.358 + ots::Buffer subtable(data, length); 1.359 + 1.360 + // Format 13 tables are simple. We parse these and fully serialise them 1.361 + // later. 1.362 + 1.363 + if (!subtable.Skip(8)) { 1.364 + return OTS_FAILURE_MSG("Bad cmap subtable length"); 1.365 + } 1.366 + uint16_t language = 0; 1.367 + if (!subtable.ReadU16(&language)) { 1.368 + return OTS_FAILURE_MSG("Can't read cmap subtable language"); 1.369 + } 1.370 + if (language) { 1.371 + return OTS_FAILURE_MSG("Cmap subtable language should be zero but is %d", language); 1.372 + } 1.373 + 1.374 + uint32_t num_groups = 0; 1.375 + if (!subtable.ReadU32(&num_groups)) { 1.376 + return OTS_FAILURE_MSG("Can't read number of groups in a cmap subtable"); 1.377 + } 1.378 + 1.379 + // We limit the number of groups in the same way as in 3.10.12 tables. See 1.380 + // the comment there in 1.381 + if (num_groups == 0 || num_groups > kMaxCMAPGroups) { 1.382 + return OTS_FAILURE_MSG("Bad number of groups (%d) in a cmap subtable", num_groups); 1.383 + } 1.384 + 1.385 + std::vector<ots::OpenTypeCMAPSubtableRange> &groups 1.386 + = file->cmap->subtable_3_10_13; 1.387 + groups.resize(num_groups); 1.388 + 1.389 + for (unsigned i = 0; i < num_groups; ++i) { 1.390 + if (!subtable.ReadU32(&groups[i].start_range) || 1.391 + !subtable.ReadU32(&groups[i].end_range) || 1.392 + !subtable.ReadU32(&groups[i].start_glyph_id)) { 1.393 + return OTS_FAILURE_MSG("Can't read subrange structure in a cmap subtable"); 1.394 + } 1.395 + 1.396 + // We conservatively limit all of the values to protect some parsers from 1.397 + // overflows 1.398 + if (groups[i].start_range > kUnicodeUpperLimit || 1.399 + groups[i].end_range > kUnicodeUpperLimit || 1.400 + groups[i].start_glyph_id > 0xFFFF) { 1.401 + 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); 1.402 + } 1.403 + 1.404 + if (groups[i].start_glyph_id >= num_glyphs) { 1.405 + return OTS_FAILURE_MSG("Subrange starting glyph id too high (%d > %d)", groups[i].start_glyph_id, num_glyphs); 1.406 + } 1.407 + } 1.408 + 1.409 + // the groups must be sorted by start code and may not overlap 1.410 + for (unsigned i = 1; i < num_groups; ++i) { 1.411 + if (groups[i].start_range <= groups[i - 1].start_range) { 1.412 + return OTS_FAILURE_MSG("Overlapping subrange starts (%d >= %d)", groups[i]. start_range, groups[i-1].start_range); 1.413 + } 1.414 + if (groups[i].start_range <= groups[i - 1].end_range) { 1.415 + return OTS_FAILURE_MSG("Overlapping subranges (%d <= %d)", groups[i].start_range, groups[i-1].end_range); 1.416 + } 1.417 + } 1.418 + 1.419 + return true; 1.420 +} 1.421 + 1.422 +bool Parse0514(ots::OpenTypeFile *file, 1.423 + const uint8_t *data, size_t length, uint16_t num_glyphs) { 1.424 + // Unicode Variation Selector table 1.425 + ots::Buffer subtable(data, length); 1.426 + 1.427 + // Format 14 tables are simple. We parse these and fully serialise them 1.428 + // later. 1.429 + 1.430 + // Skip format (USHORT) and length (ULONG) 1.431 + if (!subtable.Skip(6)) { 1.432 + return OTS_FAILURE_MSG("Can't read start of cmap subtable"); 1.433 + } 1.434 + 1.435 + uint32_t num_records = 0; 1.436 + if (!subtable.ReadU32(&num_records)) { 1.437 + return OTS_FAILURE_MSG("Can't read number of records in cmap subtable"); 1.438 + } 1.439 + if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) { 1.440 + return OTS_FAILURE_MSG("Bad number of records (%d) in cmap subtable", num_records); 1.441 + } 1.442 + 1.443 + std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records 1.444 + = file->cmap->subtable_0_5_14; 1.445 + records.resize(num_records); 1.446 + 1.447 + for (unsigned i = 0; i < num_records; ++i) { 1.448 + if (!subtable.ReadU24(&records[i].var_selector) || 1.449 + !subtable.ReadU32(&records[i].default_offset) || 1.450 + !subtable.ReadU32(&records[i].non_default_offset)) { 1.451 + return OTS_FAILURE_MSG("Can't read record structure of record %d in cmap subtale", i); 1.452 + } 1.453 + // Checks the value of variation selector 1.454 + if (!((records[i].var_selector >= kMongolianVSStart && 1.455 + records[i].var_selector <= kMongolianVSEnd) || 1.456 + (records[i].var_selector >= kVSStart && 1.457 + records[i].var_selector <= kVSEnd) || 1.458 + (records[i].var_selector >= kIVSStart && 1.459 + records[i].var_selector <= kIVSEnd))) { 1.460 + return OTS_FAILURE_MSG("Bad record variation selector (%04X) in record %i", records[i].var_selector, i); 1.461 + } 1.462 + if (i > 0 && 1.463 + records[i-1].var_selector >= records[i].var_selector) { 1.464 + return OTS_FAILURE_MSG("Out of order variation selector (%04X >= %04X) in record %d", records[i-1].var_selector, records[i].var_selector, i); 1.465 + } 1.466 + 1.467 + // Checks offsets 1.468 + if (!records[i].default_offset && !records[i].non_default_offset) { 1.469 + return OTS_FAILURE_MSG("No default aoffset in variation selector record %d", i); 1.470 + } 1.471 + if (records[i].default_offset && 1.472 + records[i].default_offset >= length) { 1.473 + return OTS_FAILURE_MSG("Default offset too high (%d >= %ld) in record %d", records[i].default_offset, length, i); 1.474 + } 1.475 + if (records[i].non_default_offset && 1.476 + records[i].non_default_offset >= length) { 1.477 + return OTS_FAILURE_MSG("Non default offset too high (%d >= %ld) in record %d", records[i].non_default_offset, length, i); 1.478 + } 1.479 + } 1.480 + 1.481 + for (unsigned i = 0; i < num_records; ++i) { 1.482 + // Checks default UVS table 1.483 + if (records[i].default_offset) { 1.484 + subtable.set_offset(records[i].default_offset); 1.485 + uint32_t num_ranges = 0; 1.486 + if (!subtable.ReadU32(&num_ranges)) { 1.487 + return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i); 1.488 + } 1.489 + if (!num_ranges || num_ranges > kMaxCMAPGroups) { 1.490 + return OTS_FAILURE_MSG("number of ranges too high (%d > %d) in record %d", num_ranges, kMaxCMAPGroups, i); 1.491 + } 1.492 + 1.493 + uint32_t last_unicode_value = 0; 1.494 + std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges 1.495 + = records[i].ranges; 1.496 + ranges.resize(num_ranges); 1.497 + 1.498 + for (unsigned j = 0; j < num_ranges; ++j) { 1.499 + if (!subtable.ReadU24(&ranges[j].unicode_value) || 1.500 + !subtable.ReadU8(&ranges[j].additional_count)) { 1.501 + return OTS_FAILURE_MSG("Can't read range info in variation selector record %d", i); 1.502 + } 1.503 + const uint32_t check_value = 1.504 + ranges[j].unicode_value + ranges[j].additional_count; 1.505 + if (ranges[j].unicode_value == 0 || 1.506 + ranges[j].unicode_value > kUnicodeUpperLimit || 1.507 + check_value > kUVSUpperLimit || 1.508 + (last_unicode_value && 1.509 + ranges[j].unicode_value <= last_unicode_value)) { 1.510 + return OTS_FAILURE_MSG("Bad Unicode value *%04X) in variation selector range %d record %d", ranges[j].unicode_value, j, i); 1.511 + } 1.512 + last_unicode_value = check_value; 1.513 + } 1.514 + } 1.515 + 1.516 + // Checks non default UVS table 1.517 + if (records[i].non_default_offset) { 1.518 + subtable.set_offset(records[i].non_default_offset); 1.519 + uint32_t num_mappings = 0; 1.520 + if (!subtable.ReadU32(&num_mappings)) { 1.521 + return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i); 1.522 + } 1.523 + if (!num_mappings || num_mappings > kMaxCMAPGroups) { 1.524 + return OTS_FAILURE_MSG("Number of mappings too high (%d) in variation selector record %d", num_mappings, i); 1.525 + } 1.526 + 1.527 + uint32_t last_unicode_value = 0; 1.528 + std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings 1.529 + = records[i].mappings; 1.530 + mappings.resize(num_mappings); 1.531 + 1.532 + for (unsigned j = 0; j < num_mappings; ++j) { 1.533 + if (!subtable.ReadU24(&mappings[j].unicode_value) || 1.534 + !subtable.ReadU16(&mappings[j].glyph_id)) { 1.535 + return OTS_FAILURE_MSG("Can't read mapping %d in variation selector record %d", j, i); 1.536 + } 1.537 + if (mappings[j].glyph_id == 0 || 1.538 + mappings[j].unicode_value == 0 || 1.539 + mappings[j].unicode_value > kUnicodeUpperLimit || 1.540 + (last_unicode_value && 1.541 + mappings[j].unicode_value <= last_unicode_value)) { 1.542 + 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); 1.543 + } 1.544 + last_unicode_value = mappings[j].unicode_value; 1.545 + } 1.546 + } 1.547 + } 1.548 + 1.549 + if (subtable.offset() != length) { 1.550 + return OTS_FAILURE_MSG("Bad subtable offset (%ld != %ld)", subtable.offset(), length); 1.551 + } 1.552 + file->cmap->subtable_0_5_14_length = subtable.offset(); 1.553 + return true; 1.554 +} 1.555 + 1.556 +bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) { 1.557 + // Mac Roman table 1.558 + ots::Buffer subtable(data, length); 1.559 + 1.560 + if (!subtable.Skip(4)) { 1.561 + return OTS_FAILURE_MSG("Bad cmap subtable"); 1.562 + } 1.563 + uint16_t language = 0; 1.564 + if (!subtable.ReadU16(&language)) { 1.565 + return OTS_FAILURE_MSG("Can't read language in cmap subtable"); 1.566 + } 1.567 + if (language) { 1.568 + // simsun.ttf has non-zero language id. 1.569 + OTS_WARNING("language id should be zero: %u", language); 1.570 + } 1.571 + 1.572 + file->cmap->subtable_1_0_0.reserve(kFormat0ArraySize); 1.573 + for (size_t i = 0; i < kFormat0ArraySize; ++i) { 1.574 + uint8_t glyph_id = 0; 1.575 + if (!subtable.ReadU8(&glyph_id)) { 1.576 + return OTS_FAILURE_MSG("Can't read glyph id at array[%ld] in cmap subtable", i); 1.577 + } 1.578 + file->cmap->subtable_1_0_0.push_back(glyph_id); 1.579 + } 1.580 + 1.581 + return true; 1.582 +} 1.583 + 1.584 +} // namespace 1.585 + 1.586 +namespace ots { 1.587 + 1.588 +bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { 1.589 + Buffer table(data, length); 1.590 + file->cmap = new OpenTypeCMAP; 1.591 + 1.592 + uint16_t version = 0; 1.593 + uint16_t num_tables = 0; 1.594 + if (!table.ReadU16(&version) || 1.595 + !table.ReadU16(&num_tables)) { 1.596 + return OTS_FAILURE_MSG("Can't read structure of cmap"); 1.597 + } 1.598 + 1.599 + if (version != 0) { 1.600 + return OTS_FAILURE_MSG("Non zero cmap version (%d)", version); 1.601 + } 1.602 + if (!num_tables) { 1.603 + return OTS_FAILURE_MSG("No subtables in cmap!"); 1.604 + } 1.605 + 1.606 + std::vector<CMAPSubtableHeader> subtable_headers; 1.607 + 1.608 + // read the subtable headers 1.609 + subtable_headers.reserve(num_tables); 1.610 + for (unsigned i = 0; i < num_tables; ++i) { 1.611 + CMAPSubtableHeader subt; 1.612 + 1.613 + if (!table.ReadU16(&subt.platform) || 1.614 + !table.ReadU16(&subt.encoding) || 1.615 + !table.ReadU32(&subt.offset)) { 1.616 + return OTS_FAILURE_MSG("Can't read subtable information cmap subtable %d", i); 1.617 + } 1.618 + 1.619 + subtable_headers.push_back(subt); 1.620 + } 1.621 + 1.622 + const size_t data_offset = table.offset(); 1.623 + 1.624 + // make sure that all the offsets are valid. 1.625 + for (unsigned i = 0; i < num_tables; ++i) { 1.626 + if (subtable_headers[i].offset > 1024 * 1024 * 1024) { 1.627 + return OTS_FAILURE_MSG("Bad subtable offset in cmap subtable %d", i); 1.628 + } 1.629 + if (subtable_headers[i].offset < data_offset || 1.630 + subtable_headers[i].offset >= length) { 1.631 + return OTS_FAILURE_MSG("Bad subtable offset (%d) in cmap subtable %d", subtable_headers[i].offset, i); 1.632 + } 1.633 + } 1.634 + 1.635 + // the format of the table is the first couple of bytes in the table. The 1.636 + // length of the table is stored in a format-specific way. 1.637 + for (unsigned i = 0; i < num_tables; ++i) { 1.638 + table.set_offset(subtable_headers[i].offset); 1.639 + if (!table.ReadU16(&subtable_headers[i].format)) { 1.640 + return OTS_FAILURE_MSG("Can't read cmap subtable header format %d", i); 1.641 + } 1.642 + 1.643 + uint16_t len = 0; 1.644 + uint16_t lang = 0; 1.645 + switch (subtable_headers[i].format) { 1.646 + case 0: 1.647 + case 4: 1.648 + if (!table.ReadU16(&len)) { 1.649 + return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i); 1.650 + } 1.651 + if (!table.ReadU16(&lang)) { 1.652 + return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i); 1.653 + } 1.654 + subtable_headers[i].length = len; 1.655 + subtable_headers[i].language = lang; 1.656 + break; 1.657 + case 12: 1.658 + case 13: 1.659 + if (!table.Skip(2)) { 1.660 + return OTS_FAILURE_MSG("Bad cmap subtable %d structure", i); 1.661 + } 1.662 + if (!table.ReadU32(&subtable_headers[i].length)) { 1.663 + return OTS_FAILURE_MSG("Can read cmap subtable %d length", i); 1.664 + } 1.665 + if (!table.ReadU32(&subtable_headers[i].language)) { 1.666 + return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i); 1.667 + } 1.668 + break; 1.669 + case 14: 1.670 + if (!table.ReadU32(&subtable_headers[i].length)) { 1.671 + return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i); 1.672 + } 1.673 + subtable_headers[i].language = 0; 1.674 + break; 1.675 + default: 1.676 + subtable_headers[i].length = 0; 1.677 + subtable_headers[i].language = 0; 1.678 + break; 1.679 + } 1.680 + } 1.681 + 1.682 + // check if the table is sorted first by platform ID, then by encoding ID. 1.683 + uint32_t last_id = 0; 1.684 + for (unsigned i = 0; i < num_tables; ++i) { 1.685 + uint32_t current_id 1.686 + = (subtable_headers[i].platform << 24) 1.687 + + (subtable_headers[i].encoding << 16) 1.688 + + subtable_headers[i].language; 1.689 + if ((i != 0) && (last_id >= current_id)) { 1.690 + return OTS_FAILURE_MSG("subtable %d with platform ID %d, encoding ID %d, language ID %d " 1.691 + "following subtable with platform ID %d, encoding ID %d, language ID %d", 1.692 + i, 1.693 + (uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id), 1.694 + (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id)); 1.695 + } 1.696 + last_id = current_id; 1.697 + } 1.698 + 1.699 + // Now, verify that all the lengths are sane 1.700 + for (unsigned i = 0; i < num_tables; ++i) { 1.701 + if (!subtable_headers[i].length) continue; 1.702 + if (subtable_headers[i].length > 1024 * 1024 * 1024) { 1.703 + return OTS_FAILURE_MSG("Bad cmap subtable %d length", i); 1.704 + } 1.705 + // We know that both the offset and length are < 1GB, so the following 1.706 + // addition doesn't overflow 1.707 + const uint32_t end_byte 1.708 + = subtable_headers[i].offset + subtable_headers[i].length; 1.709 + if (end_byte > length) { 1.710 + return OTS_FAILURE_MSG("Over long cmap subtable %d @ %d for %d", i, subtable_headers[i].offset, subtable_headers[i].length); 1.711 + } 1.712 + } 1.713 + 1.714 + // check that the cmap subtables are not overlapping. 1.715 + std::set<std::pair<uint32_t, uint32_t> > uniq_checker; 1.716 + std::vector<std::pair<uint32_t, uint8_t> > overlap_checker; 1.717 + for (unsigned i = 0; i < num_tables; ++i) { 1.718 + const uint32_t end_byte 1.719 + = subtable_headers[i].offset + subtable_headers[i].length; 1.720 + 1.721 + if (!uniq_checker.insert(std::make_pair(subtable_headers[i].offset, 1.722 + end_byte)).second) { 1.723 + // Sometimes Unicode table and MS table share exactly the same data. 1.724 + // We'll allow this. 1.725 + continue; 1.726 + } 1.727 + overlap_checker.push_back( 1.728 + std::make_pair(subtable_headers[i].offset, 1.729 + static_cast<uint8_t>(1) /* start */)); 1.730 + overlap_checker.push_back( 1.731 + std::make_pair(end_byte, static_cast<uint8_t>(0) /* end */)); 1.732 + } 1.733 + std::sort(overlap_checker.begin(), overlap_checker.end()); 1.734 + int overlap_count = 0; 1.735 + for (unsigned i = 0; i < overlap_checker.size(); ++i) { 1.736 + overlap_count += (overlap_checker[i].second ? 1 : -1); 1.737 + if (overlap_count > 1) { 1.738 + return OTS_FAILURE_MSG("Excessive overlap count %d", overlap_count); 1.739 + } 1.740 + } 1.741 + 1.742 + // we grab the number of glyphs in the file from the maxp table to make sure 1.743 + // that the character map isn't referencing anything beyound this range. 1.744 + if (!file->maxp) { 1.745 + return OTS_FAILURE_MSG("No maxp table in font! Needed by cmap."); 1.746 + } 1.747 + const uint16_t num_glyphs = file->maxp->num_glyphs; 1.748 + 1.749 + // We only support a subset of the possible character map tables. Microsoft 1.750 + // 'strongly recommends' that everyone supports the Unicode BMP table with 1.751 + // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables: 1.752 + // Platform ID Encoding ID Format 1.753 + // 0 0 4 (Unicode Default) 1.754 + // 0 3 4 (Unicode BMP) 1.755 + // 0 3 12 (Unicode UCS-4) 1.756 + // 0 5 14 (Unicode Variation Sequences) 1.757 + // 1 0 0 (Mac Roman) 1.758 + // 3 0 4 (MS Symbol) 1.759 + // 3 1 4 (MS Unicode BMP) 1.760 + // 3 10 12 (MS Unicode UCS-4) 1.761 + // 3 10 13 (MS UCS-4 Fallback mapping) 1.762 + // 1.763 + // Note: 1.764 + // * 0-0-4 table is (usually) written as a 3-1-4 table. If 3-1-4 table 1.765 + // also exists, the 0-0-4 table is ignored. 1.766 + // * Unlike 0-0-4 table, 0-3-4 table is written as a 0-3-4 table. 1.767 + // Some fonts which include 0-5-14 table seems to be required 0-3-4 1.768 + // table. The 0-3-4 table will be wriiten even if 3-1-4 table also exists. 1.769 + // * 0-3-12 table is written as a 3-10-12 table. If 3-10-12 table also 1.770 + // exists, the 0-3-12 table is ignored. 1.771 + // 1.772 + 1.773 + for (unsigned i = 0; i < num_tables; ++i) { 1.774 + if (subtable_headers[i].platform == 0) { 1.775 + // Unicode platform 1.776 + 1.777 + if ((subtable_headers[i].encoding == 0) && 1.778 + (subtable_headers[i].format == 4)) { 1.779 + // parse and output the 0-0-4 table as 3-1-4 table. Sometimes the 0-0-4 1.780 + // table actually points to MS symbol data and thus should be parsed as 1.781 + // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be 1.782 + // recovered in ots_cmap_serialise(). 1.783 + if (!ParseFormat4(file, 3, 1, data + subtable_headers[i].offset, 1.784 + subtable_headers[i].length, num_glyphs)) { 1.785 + return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i); 1.786 + } 1.787 + } else if ((subtable_headers[i].encoding == 3) && 1.788 + (subtable_headers[i].format == 4)) { 1.789 + // parse and output the 0-3-4 table as 0-3-4 table. 1.790 + if (!ParseFormat4(file, 0, 3, data + subtable_headers[i].offset, 1.791 + subtable_headers[i].length, num_glyphs)) { 1.792 + return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i); 1.793 + } 1.794 + } else if ((subtable_headers[i].encoding == 3) && 1.795 + (subtable_headers[i].format == 12)) { 1.796 + // parse and output the 0-3-12 table as 3-10-12 table. 1.797 + if (!Parse31012(file, data + subtable_headers[i].offset, 1.798 + subtable_headers[i].length, num_glyphs)) { 1.799 + return OTS_FAILURE_MSG("Failed to parse format 12 cmap subtable %d", i); 1.800 + } 1.801 + } else if ((subtable_headers[i].encoding == 5) && 1.802 + (subtable_headers[i].format == 14)) { 1.803 + if (!Parse0514(file, data + subtable_headers[i].offset, 1.804 + subtable_headers[i].length, num_glyphs)) { 1.805 + return OTS_FAILURE_MSG("Failed to parse format 14 cmap subtable %d", i); 1.806 + } 1.807 + } 1.808 + } else if (subtable_headers[i].platform == 1) { 1.809 + // Mac platform 1.810 + 1.811 + if ((subtable_headers[i].encoding == 0) && 1.812 + (subtable_headers[i].format == 0)) { 1.813 + // parse and output the 1-0-0 table. 1.814 + if (!Parse100(file, data + subtable_headers[i].offset, 1.815 + subtable_headers[i].length)) { 1.816 + return OTS_FAILURE(); 1.817 + } 1.818 + } 1.819 + } else if (subtable_headers[i].platform == 3) { 1.820 + // MS platform 1.821 + 1.822 + switch (subtable_headers[i].encoding) { 1.823 + case 0: 1.824 + case 1: 1.825 + if (subtable_headers[i].format == 4) { 1.826 + // parse 3-0-4 or 3-1-4 table. 1.827 + if (!ParseFormat4(file, subtable_headers[i].platform, 1.828 + subtable_headers[i].encoding, 1.829 + data + subtable_headers[i].offset, 1.830 + subtable_headers[i].length, num_glyphs)) { 1.831 + return OTS_FAILURE(); 1.832 + } 1.833 + } 1.834 + break; 1.835 + case 10: 1.836 + if (subtable_headers[i].format == 12) { 1.837 + file->cmap->subtable_3_10_12.clear(); 1.838 + if (!Parse31012(file, data + subtable_headers[i].offset, 1.839 + subtable_headers[i].length, num_glyphs)) { 1.840 + return OTS_FAILURE(); 1.841 + } 1.842 + } else if (subtable_headers[i].format == 13) { 1.843 + file->cmap->subtable_3_10_13.clear(); 1.844 + if (!Parse31013(file, data + subtable_headers[i].offset, 1.845 + subtable_headers[i].length, num_glyphs)) { 1.846 + return OTS_FAILURE(); 1.847 + } 1.848 + } 1.849 + break; 1.850 + } 1.851 + } 1.852 + } 1.853 + 1.854 + return true; 1.855 +} 1.856 + 1.857 +bool ots_cmap_should_serialise(OpenTypeFile *file) { 1.858 + return file->cmap != NULL; 1.859 +} 1.860 + 1.861 +bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) { 1.862 + const bool have_034 = file->cmap->subtable_0_3_4_data != NULL; 1.863 + const bool have_0514 = file->cmap->subtable_0_5_14.size() != 0; 1.864 + const bool have_100 = file->cmap->subtable_1_0_0.size() != 0; 1.865 + const bool have_304 = file->cmap->subtable_3_0_4_data != NULL; 1.866 + // MS Symbol and MS Unicode tables should not co-exist. 1.867 + // See the comment above in 0-0-4 parser. 1.868 + const bool have_314 = (!have_304) && file->cmap->subtable_3_1_4_data; 1.869 + const bool have_31012 = file->cmap->subtable_3_10_12.size() != 0; 1.870 + const bool have_31013 = file->cmap->subtable_3_10_13.size() != 0; 1.871 + const unsigned num_subtables = static_cast<unsigned>(have_034) + 1.872 + static_cast<unsigned>(have_0514) + 1.873 + static_cast<unsigned>(have_100) + 1.874 + static_cast<unsigned>(have_304) + 1.875 + static_cast<unsigned>(have_314) + 1.876 + static_cast<unsigned>(have_31012) + 1.877 + static_cast<unsigned>(have_31013); 1.878 + const off_t table_start = out->Tell(); 1.879 + 1.880 + // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables 1.881 + // (e.g., old fonts for Mac). We don't support them. 1.882 + if (!have_304 && !have_314 && !have_034) { 1.883 + return OTS_FAILURE(); 1.884 + } 1.885 + 1.886 + if (!out->WriteU16(0) || 1.887 + !out->WriteU16(num_subtables)) { 1.888 + return OTS_FAILURE(); 1.889 + } 1.890 + 1.891 + const off_t record_offset = out->Tell(); 1.892 + if (!out->Pad(num_subtables * 8)) { 1.893 + return OTS_FAILURE(); 1.894 + } 1.895 + 1.896 + const off_t offset_034 = out->Tell(); 1.897 + if (have_034) { 1.898 + if (!out->Write(file->cmap->subtable_0_3_4_data, 1.899 + file->cmap->subtable_0_3_4_length)) { 1.900 + return OTS_FAILURE(); 1.901 + } 1.902 + } 1.903 + 1.904 + const off_t offset_0514 = out->Tell(); 1.905 + if (have_0514) { 1.906 + const std::vector<ots::OpenTypeCMAPSubtableVSRecord> &records 1.907 + = file->cmap->subtable_0_5_14; 1.908 + const unsigned num_records = records.size(); 1.909 + if (!out->WriteU16(14) || 1.910 + !out->WriteU32(file->cmap->subtable_0_5_14_length) || 1.911 + !out->WriteU32(num_records)) { 1.912 + return OTS_FAILURE(); 1.913 + } 1.914 + for (unsigned i = 0; i < num_records; ++i) { 1.915 + if (!out->WriteU24(records[i].var_selector) || 1.916 + !out->WriteU32(records[i].default_offset) || 1.917 + !out->WriteU32(records[i].non_default_offset)) { 1.918 + return OTS_FAILURE(); 1.919 + } 1.920 + } 1.921 + for (unsigned i = 0; i < num_records; ++i) { 1.922 + if (records[i].default_offset) { 1.923 + const std::vector<ots::OpenTypeCMAPSubtableVSRange> &ranges 1.924 + = records[i].ranges; 1.925 + const unsigned num_ranges = ranges.size(); 1.926 + if (!out->Seek(records[i].default_offset + offset_0514) || 1.927 + !out->WriteU32(num_ranges)) { 1.928 + return OTS_FAILURE(); 1.929 + } 1.930 + for (unsigned j = 0; j < num_ranges; ++j) { 1.931 + if (!out->WriteU24(ranges[j].unicode_value) || 1.932 + !out->WriteU8(ranges[j].additional_count)) { 1.933 + return OTS_FAILURE(); 1.934 + } 1.935 + } 1.936 + } 1.937 + if (records[i].non_default_offset) { 1.938 + const std::vector<ots::OpenTypeCMAPSubtableVSMapping> &mappings 1.939 + = records[i].mappings; 1.940 + const unsigned num_mappings = mappings.size(); 1.941 + if (!out->Seek(records[i].non_default_offset + offset_0514) || 1.942 + !out->WriteU32(num_mappings)) { 1.943 + return OTS_FAILURE(); 1.944 + } 1.945 + for (unsigned j = 0; j < num_mappings; ++j) { 1.946 + if (!out->WriteU24(mappings[j].unicode_value) || 1.947 + !out->WriteU16(mappings[j].glyph_id)) { 1.948 + return OTS_FAILURE(); 1.949 + } 1.950 + } 1.951 + } 1.952 + } 1.953 + } 1.954 + 1.955 + const off_t offset_100 = out->Tell(); 1.956 + if (have_100) { 1.957 + if (!out->WriteU16(0) || // format 1.958 + !out->WriteU16(6 + kFormat0ArraySize) || // length 1.959 + !out->WriteU16(0)) { // language 1.960 + return OTS_FAILURE(); 1.961 + } 1.962 + if (!out->Write(&(file->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) { 1.963 + return OTS_FAILURE(); 1.964 + } 1.965 + } 1.966 + 1.967 + const off_t offset_304 = out->Tell(); 1.968 + if (have_304) { 1.969 + if (!out->Write(file->cmap->subtable_3_0_4_data, 1.970 + file->cmap->subtable_3_0_4_length)) { 1.971 + return OTS_FAILURE(); 1.972 + } 1.973 + } 1.974 + 1.975 + const off_t offset_314 = out->Tell(); 1.976 + if (have_314) { 1.977 + if (!out->Write(file->cmap->subtable_3_1_4_data, 1.978 + file->cmap->subtable_3_1_4_length)) { 1.979 + return OTS_FAILURE(); 1.980 + } 1.981 + } 1.982 + 1.983 + const off_t offset_31012 = out->Tell(); 1.984 + if (have_31012) { 1.985 + std::vector<OpenTypeCMAPSubtableRange> &groups 1.986 + = file->cmap->subtable_3_10_12; 1.987 + const unsigned num_groups = groups.size(); 1.988 + if (!out->WriteU16(12) || 1.989 + !out->WriteU16(0) || 1.990 + !out->WriteU32(num_groups * 12 + 16) || 1.991 + !out->WriteU32(0) || 1.992 + !out->WriteU32(num_groups)) { 1.993 + return OTS_FAILURE(); 1.994 + } 1.995 + 1.996 + for (unsigned i = 0; i < num_groups; ++i) { 1.997 + if (!out->WriteU32(groups[i].start_range) || 1.998 + !out->WriteU32(groups[i].end_range) || 1.999 + !out->WriteU32(groups[i].start_glyph_id)) { 1.1000 + return OTS_FAILURE(); 1.1001 + } 1.1002 + } 1.1003 + } 1.1004 + 1.1005 + const off_t offset_31013 = out->Tell(); 1.1006 + if (have_31013) { 1.1007 + std::vector<OpenTypeCMAPSubtableRange> &groups 1.1008 + = file->cmap->subtable_3_10_13; 1.1009 + const unsigned num_groups = groups.size(); 1.1010 + if (!out->WriteU16(13) || 1.1011 + !out->WriteU16(0) || 1.1012 + !out->WriteU32(num_groups * 12 + 14) || 1.1013 + !out->WriteU32(0) || 1.1014 + !out->WriteU32(num_groups)) { 1.1015 + return OTS_FAILURE(); 1.1016 + } 1.1017 + 1.1018 + for (unsigned i = 0; i < num_groups; ++i) { 1.1019 + if (!out->WriteU32(groups[i].start_range) || 1.1020 + !out->WriteU32(groups[i].end_range) || 1.1021 + !out->WriteU32(groups[i].start_glyph_id)) { 1.1022 + return OTS_FAILURE(); 1.1023 + } 1.1024 + } 1.1025 + } 1.1026 + 1.1027 + const off_t table_end = out->Tell(); 1.1028 + // We might have hanging bytes from the above's checksum which the OTSStream 1.1029 + // then merges into the table of offsets. 1.1030 + OTSStream::ChecksumState saved_checksum = out->SaveChecksumState(); 1.1031 + out->ResetChecksum(); 1.1032 + 1.1033 + // Now seek back and write the table of offsets 1.1034 + if (!out->Seek(record_offset)) { 1.1035 + return OTS_FAILURE(); 1.1036 + } 1.1037 + 1.1038 + if (have_034) { 1.1039 + if (!out->WriteU16(0) || 1.1040 + !out->WriteU16(3) || 1.1041 + !out->WriteU32(offset_034 - table_start)) { 1.1042 + return OTS_FAILURE(); 1.1043 + } 1.1044 + } 1.1045 + 1.1046 + if (have_0514) { 1.1047 + if (!out->WriteU16(0) || 1.1048 + !out->WriteU16(5) || 1.1049 + !out->WriteU32(offset_0514 - table_start)) { 1.1050 + return OTS_FAILURE(); 1.1051 + } 1.1052 + } 1.1053 + 1.1054 + if (have_100) { 1.1055 + if (!out->WriteU16(1) || 1.1056 + !out->WriteU16(0) || 1.1057 + !out->WriteU32(offset_100 - table_start)) { 1.1058 + return OTS_FAILURE(); 1.1059 + } 1.1060 + } 1.1061 + 1.1062 + if (have_304) { 1.1063 + if (!out->WriteU16(3) || 1.1064 + !out->WriteU16(0) || 1.1065 + !out->WriteU32(offset_304 - table_start)) { 1.1066 + return OTS_FAILURE(); 1.1067 + } 1.1068 + } 1.1069 + 1.1070 + if (have_314) { 1.1071 + if (!out->WriteU16(3) || 1.1072 + !out->WriteU16(1) || 1.1073 + !out->WriteU32(offset_314 - table_start)) { 1.1074 + return OTS_FAILURE(); 1.1075 + } 1.1076 + } 1.1077 + 1.1078 + if (have_31012) { 1.1079 + if (!out->WriteU16(3) || 1.1080 + !out->WriteU16(10) || 1.1081 + !out->WriteU32(offset_31012 - table_start)) { 1.1082 + return OTS_FAILURE(); 1.1083 + } 1.1084 + } 1.1085 + 1.1086 + if (have_31013) { 1.1087 + if (!out->WriteU16(3) || 1.1088 + !out->WriteU16(10) || 1.1089 + !out->WriteU32(offset_31013 - table_start)) { 1.1090 + return OTS_FAILURE(); 1.1091 + } 1.1092 + } 1.1093 + 1.1094 + if (!out->Seek(table_end)) { 1.1095 + return OTS_FAILURE(); 1.1096 + } 1.1097 + out->RestoreChecksum(saved_checksum); 1.1098 + 1.1099 + return true; 1.1100 +} 1.1101 + 1.1102 +void ots_cmap_free(OpenTypeFile *file) { 1.1103 + delete file->cmap; 1.1104 +} 1.1105 + 1.1106 +} // namespace ots