| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 // This is the implementation of decompression of the proposed WOFF Ultra | 5 // This is the implementation of decompression of the proposed WOFF Ultra |
| 6 // Condensed file format. | 6 // Condensed file format. |
| 7 | 7 |
| 8 #include <cassert> | 8 #include <cassert> |
| 9 #include <cstdlib> | 9 #include <cstdlib> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 } | 175 } |
| 176 } | 176 } |
| 177 | 177 |
| 178 bool ReadBase128(ots::Buffer* buf, uint32_t* value) { | 178 bool ReadBase128(ots::Buffer* buf, uint32_t* value) { |
| 179 uint32_t result = 0; | 179 uint32_t result = 0; |
| 180 for (size_t i = 0; i < 5; ++i) { | 180 for (size_t i = 0; i < 5; ++i) { |
| 181 uint8_t code = 0; | 181 uint8_t code = 0; |
| 182 if (!buf->ReadU8(&code)) { | 182 if (!buf->ReadU8(&code)) { |
| 183 return OTS_FAILURE(); | 183 return OTS_FAILURE(); |
| 184 } | 184 } |
| 185 if (i == 0 && code == 0x80) { |
| 186 return OTS_FAILURE(); |
| 187 } |
| 185 // If any of the top seven bits are set then we're about to overflow. | 188 // If any of the top seven bits are set then we're about to overflow. |
| 186 if (result & 0xfe000000U) { | 189 if (result & 0xfe000000U) { |
| 187 return OTS_FAILURE(); | 190 return OTS_FAILURE(); |
| 188 } | 191 } |
| 189 result = (result << 7) | (code & 0x7f); | 192 result = (result << 7) | (code & 0x7f); |
| 190 if ((code & 0x80) == 0) { | 193 if ((code & 0x80) == 0) { |
| 191 *value = result; | 194 *value = result; |
| 192 return true; | 195 return true; |
| 193 } | 196 } |
| 194 } | 197 } |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 if (index_format) { | 506 if (index_format) { |
| 504 offset = StoreU32(dst, offset, value); | 507 offset = StoreU32(dst, offset, value); |
| 505 } else { | 508 } else { |
| 506 offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1)); | 509 offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1)); |
| 507 } | 510 } |
| 508 } | 511 } |
| 509 return true; | 512 return true; |
| 510 } | 513 } |
| 511 | 514 |
| 512 // Reconstruct entire glyf table based on transformed original | 515 // Reconstruct entire glyf table based on transformed original |
| 513 bool ReconstructGlyf(ots::OpenTypeFile* file, | 516 bool ReconstructGlyf(ots::Font *font, |
| 514 const uint8_t* data, size_t data_size, | 517 const uint8_t* data, size_t data_size, |
| 515 uint8_t* dst, size_t dst_size, | 518 uint8_t* dst, size_t dst_size, |
| 516 uint8_t* loca_buf, size_t loca_size) { | 519 uint8_t* loca_buf, size_t loca_size) { |
| 517 static const int kNumSubStreams = 7; | 520 static const int kNumSubStreams = 7; |
| 518 ots::Buffer buffer(data, data_size); | 521 ots::Buffer buffer(data, data_size); |
| 519 uint32_t version; | 522 uint32_t version; |
| 520 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams); | 523 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams); |
| 521 | 524 |
| 522 if (!buffer.ReadU32(&version)) { | 525 if (!buffer.ReadU32(&version)) { |
| 523 return OTS_FAILURE_MSG("Failed to read 'version' of transformed 'glyf' table
"); | 526 return OTS_FAILURE_MSG("Failed to read 'version' of transformed 'glyf' table
"); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 553 ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second); | 556 ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second); |
| 554 ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second); | 557 ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second); |
| 555 ots::Buffer instruction_stream(substreams.at(6).first, | 558 ots::Buffer instruction_stream(substreams.at(6).first, |
| 556 substreams.at(6).second); | 559 substreams.at(6).second); |
| 557 | 560 |
| 558 std::vector<uint32_t> loca_values; | 561 std::vector<uint32_t> loca_values; |
| 559 loca_values.reserve(num_glyphs + 1); | 562 loca_values.reserve(num_glyphs + 1); |
| 560 std::vector<uint16_t> n_points_vec; | 563 std::vector<uint16_t> n_points_vec; |
| 561 std::vector<Point> points; | 564 std::vector<Point> points; |
| 562 uint32_t loca_offset = 0; | 565 uint32_t loca_offset = 0; |
| 566 const uint8_t* bbox_bitmap = bbox_stream.buffer(); |
| 563 for (unsigned int i = 0; i < num_glyphs; ++i) { | 567 for (unsigned int i = 0; i < num_glyphs; ++i) { |
| 564 size_t glyph_size = 0; | 568 size_t glyph_size = 0; |
| 565 uint16_t n_contours = 0; | 569 uint16_t n_contours = 0; |
| 566 if (!n_contour_stream.ReadU16(&n_contours)) { | 570 if (!n_contour_stream.ReadU16(&n_contours)) { |
| 567 return OTS_FAILURE_MSG("Filed to read 'numberOfContours' of glyph %d from
transformed 'glyf' table", i); | 571 return OTS_FAILURE_MSG("Filed to read 'numberOfContours' of glyph %d from
transformed 'glyf' table", i); |
| 568 } | 572 } |
| 569 uint8_t* glyf_dst = dst + loca_offset; | 573 uint8_t* glyf_dst = dst + loca_offset; |
| 570 size_t glyf_dst_size = dst_size - loca_offset; | 574 size_t glyf_dst_size = dst_size - loca_offset; |
| 571 if (n_contours == 0xffff) { | 575 if (n_contours == 0xffff) { |
| 572 // composite glyph | 576 // composite glyph |
| 577 if (!(bbox_bitmap[i >> 3] & (0x80 >> (i & 7)))) { |
| 578 return OTS_FAILURE_MSG("Composite glyph %d without bbox", i); |
| 579 } |
| 573 bool have_instructions = false; | 580 bool have_instructions = false; |
| 574 uint16_t instruction_size = 0; | 581 uint16_t instruction_size = 0; |
| 575 if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size, | 582 if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size, |
| 576 &glyph_size, &have_instructions)) { | 583 &glyph_size, &have_instructions)) { |
| 577 return OTS_FAILURE_MSG("Filed to process composite glyph %d from transfo
rmed 'glyf' table", i); | 584 return OTS_FAILURE_MSG("Filed to process composite glyph %d from transfo
rmed 'glyf' table", i); |
| 578 } | 585 } |
| 579 if (have_instructions) { | 586 if (have_instructions) { |
| 580 if (!Read255UShort(&glyph_stream, &instruction_size)) { | 587 if (!Read255UShort(&glyph_stream, &instruction_size)) { |
| 581 return OTS_FAILURE_MSG("Failed to read 'instructionLength' of glyph %d
from transformed 'glyf' table", i); | 588 return OTS_FAILURE_MSG("Failed to read 'instructionLength' of glyph %d
from transformed 'glyf' table", i); |
| 582 } | 589 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 690 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) { | 697 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) { |
| 691 size_t n_tables = tables.size(); | 698 size_t n_tables = tables.size(); |
| 692 for (size_t i = 0; i < n_tables; ++i) { | 699 for (size_t i = 0; i < n_tables; ++i) { |
| 693 if (tables.at(i).tag == tag) { | 700 if (tables.at(i).tag == tag) { |
| 694 return &tables.at(i); | 701 return &tables.at(i); |
| 695 } | 702 } |
| 696 } | 703 } |
| 697 return NULL; | 704 return NULL; |
| 698 } | 705 } |
| 699 | 706 |
| 700 bool ReconstructTransformed(ots::OpenTypeFile* file, | 707 bool ReconstructTransformed(ots::Font *font, |
| 701 const std::vector<Table>& tables, uint32_t tag, | 708 const std::vector<Table>& tables, uint32_t tag, |
| 702 const uint8_t* transformed_buf, size_t transformed_size, | 709 const uint8_t* transformed_buf, size_t transformed_size, |
| 703 uint8_t* dst, size_t dst_length) { | 710 uint8_t* dst, size_t dst_length) { |
| 704 if (tag == OTS_TAG('g','l','y','f')) { | 711 if (tag == OTS_TAG('g','l','y','f')) { |
| 705 const Table* glyf_table = FindTable(tables, tag); | 712 const Table* glyf_table = FindTable(tables, tag); |
| 706 const Table* loca_table = FindTable(tables, OTS_TAG('l','o','c','a')); | 713 const Table* loca_table = FindTable(tables, OTS_TAG('l','o','c','a')); |
| 707 if (glyf_table == NULL || loca_table == NULL) { | 714 if (glyf_table == NULL || loca_table == NULL) { |
| 708 return OTS_FAILURE(); | 715 return OTS_FAILURE(); |
| 709 } | 716 } |
| 710 if (static_cast<uint64_t>(glyf_table->dst_offset) + glyf_table->dst_length > | 717 if (static_cast<uint64_t>(glyf_table->dst_offset) + glyf_table->dst_length > |
| 711 dst_length) { | 718 dst_length) { |
| 712 return OTS_FAILURE(); | 719 return OTS_FAILURE(); |
| 713 } | 720 } |
| 714 if (static_cast<uint64_t>(loca_table->dst_offset) + loca_table->dst_length > | 721 if (static_cast<uint64_t>(loca_table->dst_offset) + loca_table->dst_length > |
| 715 dst_length) { | 722 dst_length) { |
| 716 return OTS_FAILURE(); | 723 return OTS_FAILURE(); |
| 717 } | 724 } |
| 718 return ReconstructGlyf(file, transformed_buf, transformed_size, | 725 return ReconstructGlyf(font, transformed_buf, transformed_size, |
| 719 dst + glyf_table->dst_offset, glyf_table->dst_length, | 726 dst + glyf_table->dst_offset, glyf_table->dst_length, |
| 720 dst + loca_table->dst_offset, loca_table->dst_length); | 727 dst + loca_table->dst_offset, loca_table->dst_length); |
| 721 } else if (tag == OTS_TAG('l','o','c','a')) { | 728 } else if (tag == OTS_TAG('l','o','c','a')) { |
| 722 // processing was already done by glyf table, but validate | 729 // processing was already done by glyf table, but validate |
| 723 if (!FindTable(tables, OTS_TAG('g','l','y','f'))) { | 730 if (!FindTable(tables, OTS_TAG('g','l','y','f'))) { |
| 724 return OTS_FAILURE(); | 731 return OTS_FAILURE(); |
| 725 } | 732 } |
| 726 } else { | 733 } else { |
| 727 // transform for the tag is not known | 734 // transform for the tag is not known |
| 728 return OTS_FAILURE(); | 735 return OTS_FAILURE(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum); | 768 StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum); |
| 762 file_checksum += checksum; // The addition is mod 2^32 | 769 file_checksum += checksum; // The addition is mod 2^32 |
| 763 } | 770 } |
| 764 file_checksum += ComputeChecksum(dst, | 771 file_checksum += ComputeChecksum(dst, |
| 765 kSfntHeaderSize + kSfntEntrySize * n_tables); | 772 kSfntHeaderSize + kSfntEntrySize * n_tables); |
| 766 uint32_t checksum_adjustment = 0xb1b0afba - file_checksum; | 773 uint32_t checksum_adjustment = 0xb1b0afba - file_checksum; |
| 767 StoreU32(dst, adjustment_offset, checksum_adjustment); | 774 StoreU32(dst, adjustment_offset, checksum_adjustment); |
| 768 return true; | 775 return true; |
| 769 } | 776 } |
| 770 | 777 |
| 771 bool ReadTableDirectory(ots::OpenTypeFile* file, | 778 bool ReadTableDirectory(ots::Font *font, |
| 772 ots::Buffer* buffer, std::vector<Table>* tables, | 779 ots::Buffer* buffer, std::vector<Table>* tables, |
| 773 size_t num_tables) { | 780 size_t num_tables) { |
| 774 for (size_t i = 0; i < num_tables; ++i) { | 781 for (size_t i = 0; i < num_tables; ++i) { |
| 775 Table* table = &tables->at(i); | 782 Table* table = &tables->at(i); |
| 776 uint8_t flag_byte; | 783 uint8_t flag_byte; |
| 777 if (!buffer->ReadU8(&flag_byte)) { | 784 if (!buffer->ReadU8(&flag_byte)) { |
| 778 return OTS_FAILURE_MSG("Failed to read the flags of table directory entry
%d", i); | 785 return OTS_FAILURE_MSG("Failed to read the flags of table directory entry
%d", i); |
| 779 } | 786 } |
| 780 uint32_t tag; | 787 uint32_t tag; |
| 781 if ((flag_byte & 0x3f) == 0x3f) { | 788 if ((flag_byte & 0x3f) == 0x3f) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 830 ots::Buffer file(data, length); | 837 ots::Buffer file(data, length); |
| 831 uint32_t total_length; | 838 uint32_t total_length; |
| 832 | 839 |
| 833 if (!file.Skip(16) || | 840 if (!file.Skip(16) || |
| 834 !file.ReadU32(&total_length)) { | 841 !file.ReadU32(&total_length)) { |
| 835 return 0; | 842 return 0; |
| 836 } | 843 } |
| 837 return total_length; | 844 return total_length; |
| 838 } | 845 } |
| 839 | 846 |
| 840 bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file, | 847 bool ConvertWOFF2ToSFNT(ots::Font *font, |
| 841 uint8_t* result, size_t result_length, | 848 uint8_t* result, size_t result_length, |
| 842 const uint8_t* data, size_t length) { | 849 const uint8_t* data, size_t length) { |
| 843 static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2" | 850 static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2" |
| 844 ots::Buffer buffer(data, length); | 851 ots::Buffer buffer(data, length); |
| 845 | 852 |
| 846 uint32_t signature; | 853 uint32_t signature; |
| 847 uint32_t flavor = 0; | 854 uint32_t flavor = 0; |
| 848 if (!buffer.ReadU32(&signature) || signature != kWoff2Signature || | 855 if (!buffer.ReadU32(&signature) || signature != kWoff2Signature || |
| 849 !buffer.ReadU32(&flavor)) { | 856 !buffer.ReadU32(&flavor)) { |
| 850 return OTS_FAILURE_MSG("Failed to read 'signature' or 'flavor', or not WOFF2
signature"); | 857 return OTS_FAILURE_MSG("Failed to read 'signature' or 'flavor', or not WOFF2
signature"); |
| 851 } | 858 } |
| 852 | 859 |
| 853 if (!IsValidVersionTag(ntohl(flavor))) { | 860 if (!IsValidVersionTag(flavor)) { |
| 854 return OTS_FAILURE_MSG("Invalid 'flavor'"); | 861 return OTS_FAILURE_MSG("Invalid 'flavor'"); |
| 855 } | 862 } |
| 856 | 863 |
| 857 uint32_t reported_length; | 864 uint32_t reported_length; |
| 858 if (!buffer.ReadU32(&reported_length) || length != reported_length) { | 865 if (!buffer.ReadU32(&reported_length) || length != reported_length) { |
| 859 return OTS_FAILURE_MSG("Failed to read 'length' or it does not match the act
ual file size"); | 866 return OTS_FAILURE_MSG("Failed to read 'length' or it does not match the act
ual file size"); |
| 860 } | 867 } |
| 861 uint16_t num_tables; | 868 uint16_t num_tables; |
| 862 if (!buffer.ReadU16(&num_tables) || !num_tables) { | 869 if (!buffer.ReadU16(&num_tables) || !num_tables) { |
| 863 return OTS_FAILURE_MSG("Failed to read 'numTables'"); | 870 return OTS_FAILURE_MSG("Failed to read 'numTables'"); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 909 !buffer.ReadU32(&priv_length)) { | 916 !buffer.ReadU32(&priv_length)) { |
| 910 return OTS_FAILURE_MSG("Failed to read header private block fields"); | 917 return OTS_FAILURE_MSG("Failed to read header private block fields"); |
| 911 } | 918 } |
| 912 if (priv_offset) { | 919 if (priv_offset) { |
| 913 if (priv_offset >= length || length - priv_offset < priv_length) { | 920 if (priv_offset >= length || length - priv_offset < priv_length) { |
| 914 return OTS_FAILURE_MSG("Invalid private block offset or length"); | 921 return OTS_FAILURE_MSG("Invalid private block offset or length"); |
| 915 } | 922 } |
| 916 } | 923 } |
| 917 | 924 |
| 918 std::vector<Table> tables(num_tables); | 925 std::vector<Table> tables(num_tables); |
| 919 if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) { | 926 if (!ReadTableDirectory(font, &buffer, &tables, num_tables)) { |
| 920 return OTS_FAILURE_MSG("Failed to read table directory"); | 927 return OTS_FAILURE_MSG("Failed to read table directory"); |
| 921 } | 928 } |
| 922 uint64_t compressed_offset = buffer.offset(); | 929 uint64_t compressed_offset = buffer.offset(); |
| 923 if (compressed_offset > std::numeric_limits<uint32_t>::max()) { | 930 if (compressed_offset > std::numeric_limits<uint32_t>::max()) { |
| 924 return OTS_FAILURE(); | 931 return OTS_FAILURE(); |
| 925 } | 932 } |
| 926 uint64_t dst_offset = kSfntHeaderSize + | 933 uint64_t dst_offset = kSfntHeaderSize + |
| 927 kSfntEntrySize * static_cast<uint64_t>(num_tables); | 934 kSfntEntrySize * static_cast<uint64_t>(num_tables); |
| 928 for (uint16_t i = 0; i < num_tables; ++i) { | 935 for (uint16_t i = 0; i < num_tables; ++i) { |
| 929 Table* table = &tables.at(i); | 936 Table* table = &tables.at(i); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1030 if (transform_length != table->dst_length) { | 1037 if (transform_length != table->dst_length) { |
| 1031 return OTS_FAILURE(); | 1038 return OTS_FAILURE(); |
| 1032 } | 1039 } |
| 1033 if (static_cast<uint64_t>(table->dst_offset) + transform_length > | 1040 if (static_cast<uint64_t>(table->dst_offset) + transform_length > |
| 1034 result_length) { | 1041 result_length) { |
| 1035 return OTS_FAILURE(); | 1042 return OTS_FAILURE(); |
| 1036 } | 1043 } |
| 1037 std::memcpy(result + table->dst_offset, transform_buf, | 1044 std::memcpy(result + table->dst_offset, transform_buf, |
| 1038 transform_length); | 1045 transform_length); |
| 1039 } else { | 1046 } else { |
| 1040 if (!ReconstructTransformed(file, tables, table->tag, | 1047 if (!ReconstructTransformed(font, tables, table->tag, |
| 1041 transform_buf, transform_length, result, result_length)) { | 1048 transform_buf, transform_length, result, result_length)) { |
| 1042 return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", OTS_UNT
AG(table->tag)); | 1049 return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", OTS_UNT
AG(table->tag)); |
| 1043 } | 1050 } |
| 1044 } | 1051 } |
| 1045 | 1052 |
| 1046 transform_buf += transform_length; | 1053 transform_buf += transform_length; |
| 1047 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) { | 1054 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) { |
| 1048 return OTS_FAILURE(); | 1055 return OTS_FAILURE(); |
| 1049 } | 1056 } |
| 1050 } | 1057 } |
| 1051 | 1058 |
| 1052 return FixChecksums(sorted_tables, result); | 1059 return FixChecksums(sorted_tables, result); |
| 1053 } | 1060 } |
| 1054 | 1061 |
| 1055 } // namespace ots | 1062 } // namespace ots |
| 1056 | 1063 |
| 1057 #undef TABLE_NAME | 1064 #undef TABLE_NAME |
| OLD | NEW |