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