| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ots.h" | 5 #include "ots.h" |
| 6 | 6 |
| 7 #include <sys/types.h> | 7 #include <sys/types.h> |
| 8 #include <zlib.h> | 8 #include <zlib.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 #include <cstdlib> | 11 #include <cstdlib> |
| 12 #include <cstring> | 12 #include <cstring> |
| 13 #include <limits> | 13 #include <limits> |
| 14 #include <map> | 14 #include <map> |
| 15 #include <vector> | 15 #include <vector> |
| 16 | 16 |
| 17 #include "woff2.h" |
| 18 |
| 17 // The OpenType Font File | 19 // The OpenType Font File |
| 18 // http://www.microsoft.com/typography/otspec/cmap.htm | 20 // http://www.microsoft.com/typography/otspec/cmap.htm |
| 19 | 21 |
| 20 namespace { | 22 namespace { |
| 21 | 23 |
| 22 bool g_debug_output = true; | 24 bool g_debug_output = true; |
| 25 bool g_enable_woff2 = false; |
| 23 | 26 |
| 24 struct OpenTypeTable { | 27 struct OpenTypeTable { |
| 25 uint32_t tag; | 28 uint32_t tag; |
| 26 uint32_t chksum; | 29 uint32_t chksum; |
| 27 uint32_t offset; | 30 uint32_t offset; |
| 28 uint32_t length; | 31 uint32_t length; |
| 29 uint32_t uncompressed_length; | 32 uint32_t uncompressed_length; |
| 30 }; | 33 }; |
| 31 | 34 |
| 32 // Round a value up to the nearest multiple of 4. Don't round the value in the | |
| 33 // case that rounding up overflows. | |
| 34 template<typename T> T Round4(T value) { | |
| 35 if (std::numeric_limits<T>::max() - value < 3) { | |
| 36 return value; | |
| 37 } | |
| 38 return (value + 3) & ~3; | |
| 39 } | |
| 40 | |
| 41 bool CheckTag(uint32_t tag_value) { | 35 bool CheckTag(uint32_t tag_value) { |
| 42 for (unsigned i = 0; i < 4; ++i) { | 36 for (unsigned i = 0; i < 4; ++i) { |
| 43 const uint32_t check = tag_value & 0xff; | 37 const uint32_t check = tag_value & 0xff; |
| 44 if (check < 32 || check > 126) { | 38 if (check < 32 || check > 126) { |
| 45 return false; // non-ASCII character found. | 39 return false; // non-ASCII character found. |
| 46 } | 40 } |
| 47 tag_value >>= 8; | 41 tag_value >>= 8; |
| 48 } | 42 } |
| 49 return true; | 43 return true; |
| 50 } | 44 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise, | 138 { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise, |
| 145 ots::ots_gsub_should_serialise, ots::ots_gsub_free, false }, | 139 ots::ots_gsub_should_serialise, ots::ots_gsub_free, false }, |
| 146 { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise, | 140 { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise, |
| 147 ots::ots_vhea_should_serialise, ots::ots_vhea_free, false }, | 141 ots::ots_vhea_should_serialise, ots::ots_vhea_free, false }, |
| 148 { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise, | 142 { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise, |
| 149 ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false }, | 143 ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false }, |
| 150 // TODO(bashi): Support mort, base, and jstf tables. | 144 // TODO(bashi): Support mort, base, and jstf tables. |
| 151 { 0, NULL, NULL, NULL, NULL, false }, | 145 { 0, NULL, NULL, NULL, NULL, false }, |
| 152 }; | 146 }; |
| 153 | 147 |
| 154 bool IsValidVersionTag(uint32_t tag) { | |
| 155 return tag == Tag("\x00\x01\x00\x00") || | |
| 156 // OpenType fonts with CFF data have 'OTTO' tag. | |
| 157 tag == Tag("OTTO") || | |
| 158 // Older Mac fonts might have 'true' or 'typ1' tag. | |
| 159 tag == Tag("true") || | |
| 160 tag == Tag("typ1"); | |
| 161 } | |
| 162 | |
| 163 bool ProcessGeneric(ots::OpenTypeFile *header, | 148 bool ProcessGeneric(ots::OpenTypeFile *header, |
| 164 uint32_t signature, | 149 uint32_t signature, |
| 165 ots::OTSStream *output, | 150 ots::OTSStream *output, |
| 166 const uint8_t *data, size_t length, | 151 const uint8_t *data, size_t length, |
| 167 const std::vector<OpenTypeTable>& tables, | 152 const std::vector<OpenTypeTable>& tables, |
| 168 ots::Buffer& file); | 153 ots::Buffer& file); |
| 169 | 154 |
| 170 bool ProcessTTF(ots::OpenTypeFile *header, | 155 bool ProcessTTF(ots::OpenTypeFile *header, |
| 171 ots::OTSStream *output, const uint8_t *data, size_t length) { | 156 ots::OTSStream *output, const uint8_t *data, size_t length) { |
| 172 ots::Buffer file(data, length); | 157 ots::Buffer file(data, length); |
| 173 | 158 |
| 174 // we disallow all files > 1GB in size for sanity. | 159 // we disallow all files > 1GB in size for sanity. |
| 175 if (length > 1024 * 1024 * 1024) { | 160 if (length > 1024 * 1024 * 1024) { |
| 176 return OTS_FAILURE(); | 161 return OTS_FAILURE(); |
| 177 } | 162 } |
| 178 | 163 |
| 179 if (!file.ReadTag(&header->version)) { | 164 if (!file.ReadTag(&header->version)) { |
| 180 return OTS_FAILURE(); | 165 return OTS_FAILURE(); |
| 181 } | 166 } |
| 182 if (!IsValidVersionTag(header->version)) { | 167 if (!ots::IsValidVersionTag(header->version)) { |
| 183 return OTS_FAILURE(); | 168 return OTS_FAILURE(); |
| 184 } | 169 } |
| 185 | 170 |
| 186 if (!file.ReadU16(&header->num_tables) || | 171 if (!file.ReadU16(&header->num_tables) || |
| 187 !file.ReadU16(&header->search_range) || | 172 !file.ReadU16(&header->search_range) || |
| 188 !file.ReadU16(&header->entry_selector) || | 173 !file.ReadU16(&header->entry_selector) || |
| 189 !file.ReadU16(&header->range_shift)) { | 174 !file.ReadU16(&header->range_shift)) { |
| 190 return OTS_FAILURE(); | 175 return OTS_FAILURE(); |
| 191 } | 176 } |
| 192 | 177 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 return OTS_FAILURE(); | 243 return OTS_FAILURE(); |
| 259 } | 244 } |
| 260 | 245 |
| 261 if (woff_tag != Tag("wOFF")) { | 246 if (woff_tag != Tag("wOFF")) { |
| 262 return OTS_FAILURE(); | 247 return OTS_FAILURE(); |
| 263 } | 248 } |
| 264 | 249 |
| 265 if (!file.ReadTag(&header->version)) { | 250 if (!file.ReadTag(&header->version)) { |
| 266 return OTS_FAILURE(); | 251 return OTS_FAILURE(); |
| 267 } | 252 } |
| 268 if (!IsValidVersionTag(header->version)) { | 253 if (!ots::IsValidVersionTag(header->version)) { |
| 269 return OTS_FAILURE(); | 254 return OTS_FAILURE(); |
| 270 } | 255 } |
| 271 | 256 |
| 272 header->search_range = 0; | 257 header->search_range = 0; |
| 273 header->entry_selector = 0; | 258 header->entry_selector = 0; |
| 274 header->range_shift = 0; | 259 header->range_shift = 0; |
| 275 | 260 |
| 276 uint32_t reported_length; | 261 uint32_t reported_length; |
| 277 if (!file.ReadU32(&reported_length) || length != reported_length) { | 262 if (!file.ReadU32(&reported_length) || length != reported_length) { |
| 278 return OTS_FAILURE(); | 263 return OTS_FAILURE(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 for (unsigned i = 0; i < header->num_tables; ++i) { | 321 for (unsigned i = 0; i < header->num_tables; ++i) { |
| 337 OpenTypeTable table; | 322 OpenTypeTable table; |
| 338 if (!file.ReadTag(&table.tag) || | 323 if (!file.ReadTag(&table.tag) || |
| 339 !file.ReadU32(&table.offset) || | 324 !file.ReadU32(&table.offset) || |
| 340 !file.ReadU32(&table.length) || | 325 !file.ReadU32(&table.length) || |
| 341 !file.ReadU32(&table.uncompressed_length) || | 326 !file.ReadU32(&table.uncompressed_length) || |
| 342 !file.ReadU32(&table.chksum)) { | 327 !file.ReadU32(&table.chksum)) { |
| 343 return OTS_FAILURE(); | 328 return OTS_FAILURE(); |
| 344 } | 329 } |
| 345 | 330 |
| 346 total_sfnt_size += Round4(table.uncompressed_length); | 331 total_sfnt_size += ots::Round4(table.uncompressed_length); |
| 347 if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) { | 332 if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) { |
| 348 return OTS_FAILURE(); | 333 return OTS_FAILURE(); |
| 349 } | 334 } |
| 350 tables.push_back(table); | 335 tables.push_back(table); |
| 351 if (i == 0 || tables[first_index].offset > table.offset) | 336 if (i == 0 || tables[first_index].offset > table.offset) |
| 352 first_index = i; | 337 first_index = i; |
| 353 if (i == 0 || tables[last_index].offset < table.offset) | 338 if (i == 0 || tables[last_index].offset < table.offset) |
| 354 last_index = i; | 339 last_index = i; |
| 355 } | 340 } |
| 356 | 341 |
| 357 if (reported_total_sfnt_size != total_sfnt_size) { | 342 if (reported_total_sfnt_size != total_sfnt_size) { |
| 358 return OTS_FAILURE(); | 343 return OTS_FAILURE(); |
| 359 } | 344 } |
| 360 | 345 |
| 361 // Table data must follow immediately after the header. | 346 // Table data must follow immediately after the header. |
| 362 if (tables[first_index].offset != Round4(file.offset())) { | 347 if (tables[first_index].offset != ots::Round4(file.offset())) { |
| 363 return OTS_FAILURE(); | 348 return OTS_FAILURE(); |
| 364 } | 349 } |
| 365 | 350 |
| 366 if (tables[last_index].offset >= length || | 351 if (tables[last_index].offset >= length || |
| 367 length - tables[last_index].offset < tables[last_index].length) { | 352 length - tables[last_index].offset < tables[last_index].length) { |
| 368 return OTS_FAILURE(); | 353 return OTS_FAILURE(); |
| 369 } | 354 } |
| 370 // Blocks must follow immediately after the previous block. | 355 // Blocks must follow immediately after the previous block. |
| 371 // (Except for padding with a maximum of three null bytes) | 356 // (Except for padding with a maximum of three null bytes) |
| 372 uint64_t block_end = Round4( | 357 uint64_t block_end = ots::Round4( |
| 373 static_cast<uint64_t>(tables[last_index].offset) + | 358 static_cast<uint64_t>(tables[last_index].offset) + |
| 374 static_cast<uint64_t>(tables[last_index].length)); | 359 static_cast<uint64_t>(tables[last_index].length)); |
| 375 if (block_end > std::numeric_limits<uint32_t>::max()) { | 360 if (block_end > std::numeric_limits<uint32_t>::max()) { |
| 376 return OTS_FAILURE(); | 361 return OTS_FAILURE(); |
| 377 } | 362 } |
| 378 if (meta_offset) { | 363 if (meta_offset) { |
| 379 if (block_end != meta_offset) { | 364 if (block_end != meta_offset) { |
| 380 return OTS_FAILURE(); | 365 return OTS_FAILURE(); |
| 381 } | 366 } |
| 382 block_end = Round4(static_cast<uint64_t>(meta_offset) + | 367 block_end = ots::Round4(static_cast<uint64_t>(meta_offset) + |
| 383 static_cast<uint64_t>(meta_length)); | 368 static_cast<uint64_t>(meta_length)); |
| 384 if (block_end > std::numeric_limits<uint32_t>::max()) { | 369 if (block_end > std::numeric_limits<uint32_t>::max()) { |
| 385 return OTS_FAILURE(); | 370 return OTS_FAILURE(); |
| 386 } | 371 } |
| 387 } | 372 } |
| 388 if (priv_offset) { | 373 if (priv_offset) { |
| 389 if (block_end != priv_offset) { | 374 if (block_end != priv_offset) { |
| 390 return OTS_FAILURE(); | 375 return OTS_FAILURE(); |
| 391 } | 376 } |
| 392 block_end = Round4(static_cast<uint64_t>(priv_offset) + | 377 block_end = ots::Round4(static_cast<uint64_t>(priv_offset) + |
| 393 static_cast<uint64_t>(priv_length)); | 378 static_cast<uint64_t>(priv_length)); |
| 394 if (block_end > std::numeric_limits<uint32_t>::max()) { | 379 if (block_end > std::numeric_limits<uint32_t>::max()) { |
| 395 return OTS_FAILURE(); | 380 return OTS_FAILURE(); |
| 396 } | 381 } |
| 397 } | 382 } |
| 398 if (block_end != Round4(length)) { | 383 if (block_end != ots::Round4(length)) { |
| 399 return OTS_FAILURE(); | 384 return OTS_FAILURE(); |
| 400 } | 385 } |
| 401 | 386 |
| 402 return ProcessGeneric(header, woff_tag, output, data, length, tables, file); | 387 return ProcessGeneric(header, woff_tag, output, data, length, tables, file); |
| 403 } | 388 } |
| 404 | 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 |
| 405 bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, | 409 bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, |
| 406 ots::OTSStream *output, | 410 ots::OTSStream *output, |
| 407 const uint8_t *data, size_t length, | 411 const uint8_t *data, size_t length, |
| 408 const std::vector<OpenTypeTable>& tables, | 412 const std::vector<OpenTypeTable>& tables, |
| 409 ots::Buffer& file) { | 413 ots::Buffer& file) { |
| 410 const size_t data_offset = file.offset(); | 414 const size_t data_offset = file.offset(); |
| 411 | 415 |
| 412 uint32_t uncompressed_sum = 0; | 416 uint32_t uncompressed_sum = 0; |
| 413 | 417 |
| 414 for (unsigned i = 0; i < header->num_tables; ++i) { | 418 for (unsigned i = 0; i < header->num_tables; ++i) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 return OTS_FAILURE(); | 464 return OTS_FAILURE(); |
| 461 } | 465 } |
| 462 | 466 |
| 463 uncompressed_sum += tables[i].uncompressed_length; | 467 uncompressed_sum += tables[i].uncompressed_length; |
| 464 } | 468 } |
| 465 // since we required that the file be < 1GB in length, and that the table | 469 // since we required that the file be < 1GB in length, and that the table |
| 466 // length is < 1GB, the following addtion doesn't overflow | 470 // length is < 1GB, the following addtion doesn't overflow |
| 467 uint32_t end_byte = tables[i].offset + tables[i].length; | 471 uint32_t end_byte = tables[i].offset + tables[i].length; |
| 468 // Tables in the WOFF file must be aligned 4-byte boundary. | 472 // Tables in the WOFF file must be aligned 4-byte boundary. |
| 469 if (signature == Tag("wOFF")) { | 473 if (signature == Tag("wOFF")) { |
| 470 end_byte = Round4(end_byte); | 474 end_byte = ots::Round4(end_byte); |
| 471 } | 475 } |
| 472 if (!end_byte || end_byte > length) { | 476 if (!end_byte || end_byte > length) { |
| 473 return OTS_FAILURE(); | 477 return OTS_FAILURE(); |
| 474 } | 478 } |
| 475 } | 479 } |
| 476 | 480 |
| 477 // All decompressed tables uncompressed must be <= 30MB. | 481 // All decompressed tables uncompressed must be <= 30MB. |
| 478 if (uncompressed_sum > 30 * 1024 * 1024) { | 482 if (uncompressed_sum > 30 * 1024 * 1024) { |
| 479 return OTS_FAILURE(); | 483 return OTS_FAILURE(); |
| 480 } | 484 } |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 return OTS_FAILURE(); | 676 return OTS_FAILURE(); |
| 673 } | 677 } |
| 674 | 678 |
| 675 return true; | 679 return true; |
| 676 } | 680 } |
| 677 | 681 |
| 678 } // namespace | 682 } // namespace |
| 679 | 683 |
| 680 namespace ots { | 684 namespace ots { |
| 681 | 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 |
| 682 void DisableDebugOutput() { | 695 void DisableDebugOutput() { |
| 683 g_debug_output = false; | 696 g_debug_output = false; |
| 684 } | 697 } |
| 685 | 698 |
| 699 void EnableWOFF2() { |
| 700 g_enable_woff2 = true; |
| 701 } |
| 702 |
| 686 bool Process(OTSStream *output, const uint8_t *data, size_t length) { | 703 bool Process(OTSStream *output, const uint8_t *data, size_t length) { |
| 687 OpenTypeFile header; | 704 OpenTypeFile header; |
| 688 if (length < 4) { | 705 if (length < 4) { |
| 689 return OTS_FAILURE(); | 706 return OTS_FAILURE(); |
| 690 } | 707 } |
| 691 | 708 |
| 692 bool result; | 709 bool result; |
| 693 if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { | 710 if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { |
| 694 result = ProcessWOFF(&header, output, data, length); | 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); |
| 695 } else { | 716 } else { |
| 696 result = ProcessTTF(&header, output, data, length); | 717 result = ProcessTTF(&header, output, data, length); |
| 697 } | 718 } |
| 698 | 719 |
| 699 for (unsigned i = 0; ; ++i) { | 720 for (unsigned i = 0; ; ++i) { |
| 700 if (table_parsers[i].parse == NULL) break; | 721 if (table_parsers[i].parse == NULL) break; |
| 701 table_parsers[i].free(&header); | 722 table_parsers[i].free(&header); |
| 702 } | 723 } |
| 703 return result; | 724 return result; |
| 704 } | 725 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 719 va_start(va, format); | 740 va_start(va, format); |
| 720 std::vfprintf(stderr, format, va); | 741 std::vfprintf(stderr, format, va); |
| 721 va_end(va); | 742 va_end(va); |
| 722 std::fprintf(stderr, "\n"); | 743 std::fprintf(stderr, "\n"); |
| 723 std::fflush(stderr); | 744 std::fflush(stderr); |
| 724 } | 745 } |
| 725 } | 746 } |
| 726 #endif | 747 #endif |
| 727 | 748 |
| 728 } // namespace ots | 749 } // namespace ots |
| OLD | NEW |