| 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 27 matching lines...) Expand all Loading... |
| 38 | 38 |
| 39 const size_t kSfntHeaderSize = 12; | 39 const size_t kSfntHeaderSize = 12; |
| 40 const size_t kSfntEntrySize = 16; | 40 const size_t kSfntEntrySize = 16; |
| 41 const size_t kCheckSumAdjustmentOffset = 8; | 41 const size_t kCheckSumAdjustmentOffset = 8; |
| 42 | 42 |
| 43 const size_t kEndPtsOfContoursOffset = 10; | 43 const size_t kEndPtsOfContoursOffset = 10; |
| 44 const size_t kCompositeGlyphBegin = 10; | 44 const size_t kCompositeGlyphBegin = 10; |
| 45 | 45 |
| 46 // Note that the byte order is big-endian, not the same as ots.cc | 46 // Note that the byte order is big-endian, not the same as ots.cc |
| 47 #define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d) | 47 #define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d) |
| 48 #define CHR(t) (t >> 24), (t >> 16), (t >> 8), (t >> 0) |
| 48 | 49 |
| 49 const unsigned int kWoff2FlagsTransform = 1 << 5; | 50 const unsigned int kWoff2FlagsTransform = 1 << 5; |
| 50 | 51 |
| 51 const uint32_t kKnownTags[] = { | 52 const uint32_t kKnownTags[] = { |
| 52 TAG('c', 'm', 'a', 'p'), // 0 | 53 TAG('c', 'm', 'a', 'p'), // 0 |
| 53 TAG('h', 'e', 'a', 'd'), // 1 | 54 TAG('h', 'e', 'a', 'd'), // 1 |
| 54 TAG('h', 'h', 'e', 'a'), // 2 | 55 TAG('h', 'h', 'e', 'a'), // 2 |
| 55 TAG('h', 'm', 't', 'x'), // 3 | 56 TAG('h', 'm', 't', 'x'), // 3 |
| 56 TAG('m', 'a', 'x', 'p'), // 4 | 57 TAG('m', 'a', 'x', 'p'), // 4 |
| 57 TAG('n', 'a', 'm', 'e'), // 5 | 58 TAG('n', 'a', 'm', 'e'), // 5 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 | 129 |
| 129 uint32_t dst_offset; | 130 uint32_t dst_offset; |
| 130 uint32_t dst_length; | 131 uint32_t dst_length; |
| 131 | 132 |
| 132 Table() | 133 Table() |
| 133 : tag(0), | 134 : tag(0), |
| 134 flags(0), | 135 flags(0), |
| 135 transform_length(0), | 136 transform_length(0), |
| 136 dst_offset(0), | 137 dst_offset(0), |
| 137 dst_length(0) {} | 138 dst_length(0) {} |
| 139 |
| 140 bool operator<(const Table& other) const { |
| 141 return tag < other.tag; |
| 142 } |
| 138 }; | 143 }; |
| 139 | 144 |
| 140 // Based on section 6.1.1 of MicroType Express draft spec | 145 // Based on section 6.1.1 of MicroType Express draft spec |
| 141 bool Read255UShort(ots::Buffer* buf, uint16_t* value) { | 146 bool Read255UShort(ots::Buffer* buf, uint16_t* value) { |
| 142 static const uint8_t kWordCode = 253; | 147 static const uint8_t kWordCode = 253; |
| 143 static const uint8_t kOneMoreByteCode2 = 254; | 148 static const uint8_t kOneMoreByteCode2 = 254; |
| 144 static const uint8_t kOneMoreByteCode1 = 255; | 149 static const uint8_t kOneMoreByteCode1 = 255; |
| 145 static const uint8_t kLowestUCode = 253; | 150 static const uint8_t kLowestUCode = 253; |
| 146 uint8_t code = 0; | 151 uint8_t code = 0; |
| 147 if (!buf->ReadU8(&code)) { | 152 if (!buf->ReadU8(&code)) { |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 if (index_format) { | 507 if (index_format) { |
| 503 offset = StoreU32(dst, offset, value); | 508 offset = StoreU32(dst, offset, value); |
| 504 } else { | 509 } else { |
| 505 offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1)); | 510 offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1)); |
| 506 } | 511 } |
| 507 } | 512 } |
| 508 return true; | 513 return true; |
| 509 } | 514 } |
| 510 | 515 |
| 511 // Reconstruct entire glyf table based on transformed original | 516 // Reconstruct entire glyf table based on transformed original |
| 512 bool ReconstructGlyf(const uint8_t* data, size_t data_size, | 517 bool ReconstructGlyf(ots::OpenTypeFile* file, |
| 518 const uint8_t* data, size_t data_size, |
| 513 uint8_t* dst, size_t dst_size, | 519 uint8_t* dst, size_t dst_size, |
| 514 uint8_t* loca_buf, size_t loca_size) { | 520 uint8_t* loca_buf, size_t loca_size) { |
| 515 static const int kNumSubStreams = 7; | 521 static const int kNumSubStreams = 7; |
| 516 ots::Buffer file(data, data_size); | 522 ots::Buffer buffer(data, data_size); |
| 517 uint32_t version; | 523 uint32_t version; |
| 518 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams); | 524 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams); |
| 519 | 525 |
| 520 if (!file.ReadU32(&version)) { | 526 if (!buffer.ReadU32(&version)) { |
| 521 return OTS_FAILURE(); | 527 return OTS_FAILURE_MSG("Failed to read 'version' of transformed 'glyf' table
"); |
| 522 } | 528 } |
| 523 uint16_t num_glyphs; | 529 uint16_t num_glyphs; |
| 530 if (!buffer.ReadU16(&num_glyphs)) { |
| 531 return OTS_FAILURE_MSG("Failed to read 'numGlyphs' from transformed 'glyf' t
able"); |
| 532 } |
| 524 uint16_t index_format; | 533 uint16_t index_format; |
| 525 if (!file.ReadU16(&num_glyphs) || | 534 if (!buffer.ReadU16(&index_format)) { |
| 526 !file.ReadU16(&index_format)) { | 535 return OTS_FAILURE_MSG("Failed to read 'indexFormat' from transformed 'glyf'
table"); |
| 527 return OTS_FAILURE(); | |
| 528 } | 536 } |
| 529 unsigned int offset = (2 + kNumSubStreams) * 4; | 537 unsigned int offset = (2 + kNumSubStreams) * 4; |
| 530 if (offset > data_size) { | 538 if (offset > data_size) { |
| 531 return OTS_FAILURE(); | 539 return OTS_FAILURE_MSG("Size of transformed 'glyf' table is too small to fit
its data"); |
| 532 } | 540 } |
| 533 // Invariant from here on: data_size >= offset | 541 // Invariant from here on: data_size >= offset |
| 534 for (int i = 0; i < kNumSubStreams; ++i) { | 542 for (int i = 0; i < kNumSubStreams; ++i) { |
| 535 uint32_t substream_size; | 543 uint32_t substream_size; |
| 536 if (!file.ReadU32(&substream_size)) { | 544 if (!buffer.ReadU32(&substream_size)) { |
| 537 return OTS_FAILURE(); | 545 return OTS_FAILURE_MSG("Failed to read substream size %d of transformed 'g
lyf' table", i); |
| 538 } | 546 } |
| 539 if (substream_size > data_size - offset) { | 547 if (substream_size > data_size - offset) { |
| 540 return OTS_FAILURE(); | 548 return OTS_FAILURE_MSG("Size of substream %d of transformed 'glyf' table d
oes not fit in table size"); |
| 541 } | 549 } |
| 542 substreams.at(i) = std::make_pair(data + offset, substream_size); | 550 substreams.at(i) = std::make_pair(data + offset, substream_size); |
| 543 offset += substream_size; | 551 offset += substream_size; |
| 544 } | 552 } |
| 545 ots::Buffer n_contour_stream(substreams.at(0).first, substreams.at(0).second); | 553 ots::Buffer n_contour_stream(substreams.at(0).first, substreams.at(0).second); |
| 546 ots::Buffer n_points_stream(substreams.at(1).first, substreams.at(1).second); | 554 ots::Buffer n_points_stream(substreams.at(1).first, substreams.at(1).second); |
| 547 ots::Buffer flag_stream(substreams.at(2).first, substreams.at(2).second); | 555 ots::Buffer flag_stream(substreams.at(2).first, substreams.at(2).second); |
| 548 ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second); | 556 ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second); |
| 549 ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second); | 557 ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second); |
| 550 ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second); | 558 ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second); |
| 551 ots::Buffer instruction_stream(substreams.at(6).first, | 559 ots::Buffer instruction_stream(substreams.at(6).first, |
| 552 substreams.at(6).second); | 560 substreams.at(6).second); |
| 553 | 561 |
| 554 std::vector<uint32_t> loca_values; | 562 std::vector<uint32_t> loca_values; |
| 555 loca_values.reserve(num_glyphs + 1); | 563 loca_values.reserve(num_glyphs + 1); |
| 556 std::vector<uint16_t> n_points_vec; | 564 std::vector<uint16_t> n_points_vec; |
| 557 std::vector<Point> points; | 565 std::vector<Point> points; |
| 558 uint32_t loca_offset = 0; | 566 uint32_t loca_offset = 0; |
| 559 for (unsigned int i = 0; i < num_glyphs; ++i) { | 567 for (unsigned int i = 0; i < num_glyphs; ++i) { |
| 560 size_t glyph_size = 0; | 568 size_t glyph_size = 0; |
| 561 uint16_t n_contours = 0; | 569 uint16_t n_contours = 0; |
| 562 if (!n_contour_stream.ReadU16(&n_contours)) { | 570 if (!n_contour_stream.ReadU16(&n_contours)) { |
| 563 return OTS_FAILURE(); | 571 return OTS_FAILURE_MSG("Filed to read 'numberOfContours' of glyph %d from
transformed 'glyf' table", i); |
| 564 } | 572 } |
| 565 uint8_t* glyf_dst = dst + loca_offset; | 573 uint8_t* glyf_dst = dst + loca_offset; |
| 566 size_t glyf_dst_size = dst_size - loca_offset; | 574 size_t glyf_dst_size = dst_size - loca_offset; |
| 567 if (n_contours == 0xffff) { | 575 if (n_contours == 0xffff) { |
| 568 // composite glyph | 576 // composite glyph |
| 569 bool have_instructions = false; | 577 bool have_instructions = false; |
| 570 uint16_t instruction_size = 0; | 578 uint16_t instruction_size = 0; |
| 571 if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size, | 579 if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size, |
| 572 &glyph_size, &have_instructions)) { | 580 &glyph_size, &have_instructions)) { |
| 573 return OTS_FAILURE(); | 581 return OTS_FAILURE_MSG("Filed to process composite glyph %d from transfo
rmed 'glyf' table", i); |
| 574 } | 582 } |
| 575 if (have_instructions) { | 583 if (have_instructions) { |
| 576 if (!Read255UShort(&glyph_stream, &instruction_size)) { | 584 if (!Read255UShort(&glyph_stream, &instruction_size)) { |
| 577 return OTS_FAILURE(); | 585 return OTS_FAILURE_MSG("Failed to read 'instructionLength' of glyph %d
from transformed 'glyf' table", i); |
| 578 } | 586 } |
| 579 // No integer overflow here (instruction_size < 2^16). | 587 // No integer overflow here (instruction_size < 2^16). |
| 580 if (instruction_size + 2U > glyf_dst_size - glyph_size) { | 588 if (instruction_size + 2U > glyf_dst_size - glyph_size) { |
| 581 return OTS_FAILURE(); | 589 return OTS_FAILURE_MSG("'instructionLength' of glyph %d from transform
ed 'glyf' table does not fit in the destination glyph size", i); |
| 582 } | 590 } |
| 583 StoreU16(glyf_dst, glyph_size, instruction_size); | 591 StoreU16(glyf_dst, glyph_size, instruction_size); |
| 584 if (!instruction_stream.Read(glyf_dst + glyph_size + 2, | 592 if (!instruction_stream.Read(glyf_dst + glyph_size + 2, |
| 585 instruction_size)) { | 593 instruction_size)) { |
| 586 return OTS_FAILURE(); | 594 return OTS_FAILURE_MSG("Filed to read instructions of glyph %d from tr
ansformed 'glyf' table", i); |
| 587 } | 595 } |
| 588 glyph_size += instruction_size + 2; | 596 glyph_size += instruction_size + 2; |
| 589 } | 597 } |
| 590 } else if (n_contours > 0) { | 598 } else if (n_contours > 0) { |
| 591 // simple glyph | 599 // simple glyph |
| 592 n_points_vec.clear(); | 600 n_points_vec.clear(); |
| 593 points.clear(); | 601 points.clear(); |
| 594 uint32_t total_n_points = 0; | 602 uint32_t total_n_points = 0; |
| 595 uint16_t n_points_contour; | 603 uint16_t n_points_contour; |
| 596 for (uint32_t j = 0; j < n_contours; ++j) { | 604 for (uint32_t j = 0; j < n_contours; ++j) { |
| 597 if (!Read255UShort(&n_points_stream, &n_points_contour)) { | 605 if (!Read255UShort(&n_points_stream, &n_points_contour)) { |
| 598 return OTS_FAILURE(); | 606 return OTS_FAILURE_MSG("Filed to read number of points of contour %d o
f glyph %d from transformed 'glyf' table", j, i); |
| 599 } | 607 } |
| 600 n_points_vec.push_back(n_points_contour); | 608 n_points_vec.push_back(n_points_contour); |
| 601 if (total_n_points + n_points_contour < total_n_points) { | 609 if (total_n_points + n_points_contour < total_n_points) { |
| 602 return OTS_FAILURE(); | 610 return OTS_FAILURE_MSG("Negative number of points of contour %d of gly
ph %d from transformed 'glyf' table", j, i); |
| 603 } | 611 } |
| 604 total_n_points += n_points_contour; | 612 total_n_points += n_points_contour; |
| 605 } | 613 } |
| 606 uint32_t flag_size = total_n_points; | 614 uint32_t flag_size = total_n_points; |
| 607 if (flag_size > flag_stream.length() - flag_stream.offset()) { | 615 if (flag_size > flag_stream.length() - flag_stream.offset()) { |
| 608 return OTS_FAILURE(); | 616 return OTS_FAILURE(); |
| 609 } | 617 } |
| 610 const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset(); | 618 const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset(); |
| 611 const uint8_t* triplet_buf = glyph_stream.buffer() + | 619 const uint8_t* triplet_buf = glyph_stream.buffer() + |
| 612 glyph_stream.offset(); | 620 glyph_stream.offset(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 647 instruction_size + 2U) { | 655 instruction_size + 2U) { |
| 648 return OTS_FAILURE(); | 656 return OTS_FAILURE(); |
| 649 } | 657 } |
| 650 uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size; | 658 uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size; |
| 651 StoreU16(instruction_dst, 0, instruction_size); | 659 StoreU16(instruction_dst, 0, instruction_size); |
| 652 if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) { | 660 if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) { |
| 653 return OTS_FAILURE(); | 661 return OTS_FAILURE(); |
| 654 } | 662 } |
| 655 if (!StorePoints(points, n_contours, instruction_size, | 663 if (!StorePoints(points, n_contours, instruction_size, |
| 656 glyf_dst, glyf_dst_size, &glyph_size)) { | 664 glyf_dst, glyf_dst_size, &glyph_size)) { |
| 657 return OTS_FAILURE(); | 665 return OTS_FAILURE_MSG("Failed to store points of glyph %d from the tran
sformed 'glyf' table", i); |
| 658 } | 666 } |
| 659 } else { | 667 } else { |
| 660 glyph_size = 0; | 668 glyph_size = 0; |
| 661 } | 669 } |
| 662 loca_values.push_back(loca_offset); | 670 loca_values.push_back(loca_offset); |
| 663 if (glyph_size + 3 < glyph_size) { | 671 if (glyph_size + 3 < glyph_size) { |
| 664 return OTS_FAILURE(); | 672 return OTS_FAILURE(); |
| 665 } | 673 } |
| 666 glyph_size = ots::Round2(glyph_size); | 674 glyph_size = ots::Round2(glyph_size); |
| 667 if (glyph_size > dst_size - loca_offset) { | 675 if (glyph_size > dst_size - loca_offset) { |
| 668 // This shouldn't happen, but this test defensively maintains the | 676 // This shouldn't happen, but this test defensively maintains the |
| 669 // invariant that loca_offset <= dst_size. | 677 // invariant that loca_offset <= dst_size. |
| 670 return OTS_FAILURE(); | 678 return OTS_FAILURE(); |
| 671 } | 679 } |
| 672 loca_offset += glyph_size; | 680 loca_offset += glyph_size; |
| 673 } | 681 } |
| 674 loca_values.push_back(loca_offset); | 682 loca_values.push_back(loca_offset); |
| 675 assert(loca_values.size() == static_cast<size_t>(num_glyphs + 1)); | 683 assert(loca_values.size() == static_cast<size_t>(num_glyphs + 1)); |
| 676 if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values, | 684 if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values, |
| 677 dst, dst_size)) { | 685 dst, dst_size)) { |
| 678 return OTS_FAILURE(); | 686 return OTS_FAILURE_MSG("Filed to process 'bboxStream' from the transformed '
glyf' table"); |
| 679 } | 687 } |
| 680 return StoreLoca(loca_values, index_format, loca_buf, loca_size); | 688 return StoreLoca(loca_values, index_format, loca_buf, loca_size); |
| 681 } | 689 } |
| 682 | 690 |
| 683 // This is linear search, but could be changed to binary because we | 691 // This is linear search, but could be changed to binary because we |
| 684 // do have a guarantee that the tables are sorted by tag. But the total | 692 // do have a guarantee that the tables are sorted by tag. But the total |
| 685 // cpu time is expected to be very small in any case. | 693 // cpu time is expected to be very small in any case. |
| 686 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) { | 694 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) { |
| 687 size_t n_tables = tables.size(); | 695 size_t n_tables = tables.size(); |
| 688 for (size_t i = 0; i < n_tables; ++i) { | 696 for (size_t i = 0; i < n_tables; ++i) { |
| 689 if (tables.at(i).tag == tag) { | 697 if (tables.at(i).tag == tag) { |
| 690 return &tables.at(i); | 698 return &tables.at(i); |
| 691 } | 699 } |
| 692 } | 700 } |
| 693 return NULL; | 701 return NULL; |
| 694 } | 702 } |
| 695 | 703 |
| 696 bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag, | 704 bool ReconstructTransformed(ots::OpenTypeFile* file, |
| 705 const std::vector<Table>& tables, uint32_t tag, |
| 697 const uint8_t* transformed_buf, size_t transformed_size, | 706 const uint8_t* transformed_buf, size_t transformed_size, |
| 698 uint8_t* dst, size_t dst_length) { | 707 uint8_t* dst, size_t dst_length) { |
| 699 if (tag == TAG('g', 'l', 'y', 'f')) { | 708 if (tag == TAG('g', 'l', 'y', 'f')) { |
| 700 const Table* glyf_table = FindTable(tables, tag); | 709 const Table* glyf_table = FindTable(tables, tag); |
| 701 const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a')); | 710 const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a')); |
| 702 if (glyf_table == NULL || loca_table == NULL) { | 711 if (glyf_table == NULL || loca_table == NULL) { |
| 703 return OTS_FAILURE(); | 712 return OTS_FAILURE(); |
| 704 } | 713 } |
| 705 if (static_cast<uint64_t>(glyf_table->dst_offset) + glyf_table->dst_length > | 714 if (static_cast<uint64_t>(glyf_table->dst_offset) + glyf_table->dst_length > |
| 706 dst_length) { | 715 dst_length) { |
| 707 return OTS_FAILURE(); | 716 return OTS_FAILURE(); |
| 708 } | 717 } |
| 709 if (static_cast<uint64_t>(loca_table->dst_offset) + loca_table->dst_length > | 718 if (static_cast<uint64_t>(loca_table->dst_offset) + loca_table->dst_length > |
| 710 dst_length) { | 719 dst_length) { |
| 711 return OTS_FAILURE(); | 720 return OTS_FAILURE(); |
| 712 } | 721 } |
| 713 return ReconstructGlyf(transformed_buf, transformed_size, | 722 return ReconstructGlyf(file, transformed_buf, transformed_size, |
| 714 dst + glyf_table->dst_offset, glyf_table->dst_length, | 723 dst + glyf_table->dst_offset, glyf_table->dst_length, |
| 715 dst + loca_table->dst_offset, loca_table->dst_length); | 724 dst + loca_table->dst_offset, loca_table->dst_length); |
| 716 } else if (tag == TAG('l', 'o', 'c', 'a')) { | 725 } else if (tag == TAG('l', 'o', 'c', 'a')) { |
| 717 // processing was already done by glyf table, but validate | 726 // processing was already done by glyf table, but validate |
| 718 if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) { | 727 if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) { |
| 719 return OTS_FAILURE(); | 728 return OTS_FAILURE(); |
| 720 } | 729 } |
| 721 } else { | 730 } else { |
| 722 // transform for the tag is not known | 731 // transform for the tag is not known |
| 723 return OTS_FAILURE(); | 732 return OTS_FAILURE(); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 return OTS_FAILURE_MSG("Bits 6 and 7 are not 0 for table directory entry %
d", i); | 805 return OTS_FAILURE_MSG("Bits 6 and 7 are not 0 for table directory entry %
d", i); |
| 797 } | 806 } |
| 798 uint32_t flags = 0; | 807 uint32_t flags = 0; |
| 799 // Always transform the glyf and loca tables | 808 // Always transform the glyf and loca tables |
| 800 if (tag == TAG('g', 'l', 'y', 'f') || | 809 if (tag == TAG('g', 'l', 'y', 'f') || |
| 801 tag == TAG('l', 'o', 'c', 'a')) { | 810 tag == TAG('l', 'o', 'c', 'a')) { |
| 802 flags |= kWoff2FlagsTransform; | 811 flags |= kWoff2FlagsTransform; |
| 803 } | 812 } |
| 804 uint32_t dst_length; | 813 uint32_t dst_length; |
| 805 if (!ReadBase128(buffer, &dst_length)) { | 814 if (!ReadBase128(buffer, &dst_length)) { |
| 806 return OTS_FAILURE_MSG("Failed to read \"origLength\" for table %4.4s", (c
har*)&tag); | 815 return OTS_FAILURE_MSG("Failed to read 'origLength' for table '%c%c%c%c'",
CHR(tag)); |
| 807 } | 816 } |
| 808 uint32_t transform_length = dst_length; | 817 uint32_t transform_length = dst_length; |
| 809 if ((flags & kWoff2FlagsTransform) != 0) { | 818 if ((flags & kWoff2FlagsTransform) != 0) { |
| 810 if (!ReadBase128(buffer, &transform_length)) { | 819 if (!ReadBase128(buffer, &transform_length)) { |
| 811 return OTS_FAILURE_MSG("Failed to read \"transformLength\" for table %4.
4s", (char*)&tag); | 820 return OTS_FAILURE_MSG("Failed to read 'transformLength' for table '%c%c
%c%c'", CHR(tag)); |
| 812 } | 821 } |
| 813 } | 822 } |
| 814 // Disallow huge numbers (> 1GB) for sanity. | 823 // Disallow huge numbers (> 1GB) for sanity. |
| 815 if (transform_length > 1024 * 1024 * 1024 || | 824 if (transform_length > 1024 * 1024 * 1024 || |
| 816 dst_length > 1024 * 1024 * 1024) { | 825 dst_length > 1024 * 1024 * 1024) { |
| 817 return OTS_FAILURE_MSG("\"origLength\" or \"transformLength\" > 1GB"); | 826 return OTS_FAILURE_MSG("'origLength' or 'transformLength' > 1GB"); |
| 818 } | 827 } |
| 819 table->tag = tag; | 828 table->tag = tag; |
| 820 table->flags = flags; | 829 table->flags = flags; |
| 821 table->transform_length = transform_length; | 830 table->transform_length = transform_length; |
| 822 table->dst_length = dst_length; | 831 table->dst_length = dst_length; |
| 823 } | 832 } |
| 824 return true; | 833 return true; |
| 825 } | 834 } |
| 826 | 835 |
| 827 } // namespace | 836 } // namespace |
| 828 | 837 |
| 829 namespace ots { | 838 namespace ots { |
| 830 | 839 |
| 831 size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) { | 840 size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) { |
| 832 ots::Buffer file(data, length); | 841 ots::Buffer file(data, length); |
| 833 uint32_t total_length; | 842 uint32_t total_length; |
| 834 | 843 |
| 835 if (!file.Skip(16) || | 844 if (!file.Skip(16) || |
| 836 !file.ReadU32(&total_length)) { | 845 !file.ReadU32(&total_length)) { |
| 837 return 0; | 846 return 0; |
| 838 } | 847 } |
| 839 return total_length; | 848 return total_length; |
| 840 } | 849 } |
| 841 | 850 |
| 842 bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file, | 851 bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file, |
| 843 uint8_t* result, size_t result_length, | 852 uint8_t* result, size_t result_length, |
| 844 const uint8_t* data, size_t length) { | 853 const uint8_t* data, size_t length) { |
| 845 static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2" | 854 static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2" |
| 846 ots::Buffer buffer(data, length); | 855 ots::Buffer buffer(data, length); |
| 847 | 856 |
| 848 uint32_t signature; | 857 uint32_t signature; |
| 849 uint32_t flavor = 0; | 858 uint32_t flavor = 0; |
| 850 if (!buffer.ReadU32(&signature) || signature != kWoff2Signature || | 859 if (!buffer.ReadU32(&signature) || signature != kWoff2Signature || |
| 851 !buffer.ReadU32(&flavor)) { | 860 !buffer.ReadU32(&flavor)) { |
| 852 return OTS_FAILURE_MSG("Failed to read \"signature\" or \"flavor\", or not W
OFF2 signature"); | 861 return OTS_FAILURE_MSG("Failed to read 'signature' or 'flavor', or not WOFF2
signature"); |
| 853 } | 862 } |
| 854 | 863 |
| 855 if (!IsValidVersionTag(ntohl(flavor))) { | 864 if (!IsValidVersionTag(ntohl(flavor))) { |
| 856 return OTS_FAILURE_MSG("Invalid \"flavor\""); | 865 return OTS_FAILURE_MSG("Invalid 'flavor'"); |
| 857 } | 866 } |
| 858 | 867 |
| 859 uint32_t reported_length; | 868 uint32_t reported_length; |
| 860 if (!buffer.ReadU32(&reported_length) || length != reported_length) { | 869 if (!buffer.ReadU32(&reported_length) || length != reported_length) { |
| 861 return OTS_FAILURE_MSG("Failed to read \"length\" or it does not match the a
ctual file size"); | 870 return OTS_FAILURE_MSG("Failed to read 'length' or it does not match the act
ual file size"); |
| 862 } | 871 } |
| 863 uint16_t num_tables; | 872 uint16_t num_tables; |
| 864 if (!buffer.ReadU16(&num_tables) || !num_tables) { | 873 if (!buffer.ReadU16(&num_tables) || !num_tables) { |
| 865 return OTS_FAILURE_MSG("Failed to read \"numTables\""); | 874 return OTS_FAILURE_MSG("Failed to read 'numTables'"); |
| 866 } | 875 } |
| 876 |
| 877 uint16_t reserved_value; |
| 878 if (!buffer.ReadU16(&reserved_value)) { |
| 879 return OTS_FAILURE_MSG("Failed to read 'reserved' field"); |
| 880 } |
| 881 |
| 867 // We don't care about these fields of the header: | 882 // We don't care about these fields of the header: |
| 868 // uint16_t reserved | 883 // uint32_t total_sfnt_size, the caller already passes it as result_length |
| 869 // uint32_t total_sfnt_size | 884 if (!buffer.Skip(4)) { |
| 870 if (!buffer.Skip(6)) { | 885 return OTS_FAILURE_MSG("Failed to read 'totalSfntSize'"); |
| 871 return OTS_FAILURE_MSG("Failed to read \"reserve\" or \"totalSfntSize\""); | |
| 872 } | 886 } |
| 873 uint32_t compressed_length; | 887 uint32_t compressed_length; |
| 874 if (!buffer.ReadU32(&compressed_length)) { | 888 if (!buffer.ReadU32(&compressed_length)) { |
| 875 return OTS_FAILURE_MSG("Failed to read \"totalCompressedSize\""); | 889 return OTS_FAILURE_MSG("Failed to read 'totalCompressedSize'"); |
| 876 } | 890 } |
| 877 if (compressed_length > std::numeric_limits<uint32_t>::max()) { | 891 if (compressed_length > std::numeric_limits<uint32_t>::max()) { |
| 878 return OTS_FAILURE(); | 892 return OTS_FAILURE(); |
| 879 } | 893 } |
| 880 | 894 |
| 881 // We don't care about these fields of the header: | 895 // We don't care about these fields of the header: |
| 882 // uint16_t major_version, minor_version | 896 // uint16_t major_version, minor_version |
| 883 // uint32_t meta_offset, meta_length, meta_orig_length | 897 if (!buffer.Skip(2 * 2)) { |
| 884 // uint32_t priv_offset, priv_length | 898 return OTS_FAILURE_MSG("Failed to read 'majorVersion' or 'minorVersion'"); |
| 885 if (!buffer.Skip(24)) { | |
| 886 return OTS_FAILURE(); | |
| 887 } | 899 } |
| 900 |
| 901 // Checks metadata block size. |
| 902 uint32_t meta_offset; |
| 903 uint32_t meta_length; |
| 904 uint32_t meta_length_orig; |
| 905 if (!buffer.ReadU32(&meta_offset) || |
| 906 !buffer.ReadU32(&meta_length) || |
| 907 !buffer.ReadU32(&meta_length_orig)) { |
| 908 return OTS_FAILURE_MSG("Failed to read header metadata block fields"); |
| 909 } |
| 910 if (meta_offset) { |
| 911 if (meta_offset >= length || length - meta_offset < meta_length) { |
| 912 return OTS_FAILURE_MSG("Invalid metadata block offset or length"); |
| 913 } |
| 914 } |
| 915 |
| 916 // Checks private data block size. |
| 917 uint32_t priv_offset; |
| 918 uint32_t priv_length; |
| 919 if (!buffer.ReadU32(&priv_offset) || |
| 920 !buffer.ReadU32(&priv_length)) { |
| 921 return OTS_FAILURE_MSG("Failed to read header private block fields"); |
| 922 } |
| 923 if (priv_offset) { |
| 924 if (priv_offset >= length || length - priv_offset < priv_length) { |
| 925 return OTS_FAILURE_MSG("Invalid private block offset or length"); |
| 926 } |
| 927 } |
| 928 |
| 888 std::vector<Table> tables(num_tables); | 929 std::vector<Table> tables(num_tables); |
| 889 if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) { | 930 if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) { |
| 890 return OTS_FAILURE_MSG("Failed to read table directory"); | 931 return OTS_FAILURE_MSG("Failed to read table directory"); |
| 891 } | 932 } |
| 892 uint64_t compressed_offset = buffer.offset(); | 933 uint64_t compressed_offset = buffer.offset(); |
| 893 if (compressed_offset > std::numeric_limits<uint32_t>::max()) { | 934 if (compressed_offset > std::numeric_limits<uint32_t>::max()) { |
| 894 return OTS_FAILURE(); | 935 return OTS_FAILURE(); |
| 895 } | 936 } |
| 896 uint64_t dst_offset = kSfntHeaderSize + | 937 uint64_t dst_offset = kSfntHeaderSize + |
| 897 kSfntEntrySize * static_cast<uint64_t>(num_tables); | 938 kSfntEntrySize * static_cast<uint64_t>(num_tables); |
| 898 for (uint16_t i = 0; i < num_tables; ++i) { | 939 for (uint16_t i = 0; i < num_tables; ++i) { |
| 899 Table* table = &tables.at(i); | 940 Table* table = &tables.at(i); |
| 900 table->dst_offset = static_cast<uint32_t>(dst_offset); | 941 table->dst_offset = static_cast<uint32_t>(dst_offset); |
| 901 dst_offset += table->dst_length; | 942 dst_offset += table->dst_length; |
| 902 if (dst_offset > std::numeric_limits<uint32_t>::max()) { | 943 if (dst_offset > std::numeric_limits<uint32_t>::max()) { |
| 903 return OTS_FAILURE(); | 944 return OTS_FAILURE(); |
| 904 } | 945 } |
| 905 dst_offset = ots::Round4(dst_offset); | 946 dst_offset = ots::Round4(dst_offset); |
| 906 } | 947 } |
| 907 if (ots::Round4(compressed_offset + compressed_length) > length || dst_offset
> result_length) { | 948 |
| 908 return OTS_FAILURE(); | 949 uint64_t block_end = ots::Round4(compressed_offset + compressed_length); |
| 950 if (block_end > length || dst_offset != result_length) { |
| 951 return OTS_FAILURE_MSG("Uncompressed sfnt size mismatch"); |
| 909 } | 952 } |
| 910 | 953 |
| 911 const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables; | 954 const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables; |
| 912 if (sfnt_header_and_table_directory_size > result_length) { | 955 if (sfnt_header_and_table_directory_size > result_length) { |
| 913 return OTS_FAILURE(); | 956 return OTS_FAILURE(); |
| 914 } | 957 } |
| 915 | 958 |
| 959 if (meta_offset) { |
| 960 if (block_end != meta_offset) { |
| 961 return OTS_FAILURE_MSG("Invalid metadata block offset"); |
| 962 } |
| 963 block_end = ots::Round4(static_cast<uint64_t>(meta_offset) + |
| 964 static_cast<uint64_t>(meta_length)); |
| 965 if (block_end > std::numeric_limits<uint32_t>::max()) { |
| 966 return OTS_FAILURE_MSG("Invalid metadata block length"); |
| 967 } |
| 968 } |
| 969 |
| 970 if (priv_offset) { |
| 971 if (block_end != priv_offset) { |
| 972 return OTS_FAILURE_MSG("Invalid private block offset"); |
| 973 } |
| 974 block_end = ots::Round4(static_cast<uint64_t>(priv_offset) + |
| 975 static_cast<uint64_t>(priv_length)); |
| 976 if (block_end > std::numeric_limits<uint32_t>::max()) { |
| 977 return OTS_FAILURE_MSG("Invalid private block length"); |
| 978 } |
| 979 } |
| 980 |
| 981 if (block_end != ots::Round4(length)) { |
| 982 return OTS_FAILURE_MSG("File length mismatch (trailing junk?)"); |
| 983 } |
| 984 |
| 916 // Start building the font | 985 // Start building the font |
| 917 size_t offset = 0; | 986 size_t offset = 0; |
| 918 offset = StoreU32(result, offset, flavor); | 987 offset = StoreU32(result, offset, flavor); |
| 919 offset = StoreU16(result, offset, num_tables); | 988 offset = StoreU16(result, offset, num_tables); |
| 920 uint8_t max_pow2 = 0; | 989 uint8_t max_pow2 = 0; |
| 921 while (1u << (max_pow2 + 1) <= num_tables) { | 990 while (1u << (max_pow2 + 1) <= num_tables) { |
| 922 max_pow2++; | 991 max_pow2++; |
| 923 } | 992 } |
| 924 const uint16_t output_search_range = (1u << max_pow2) << 4; | 993 const uint16_t output_search_range = (1u << max_pow2) << 4; |
| 925 offset = StoreU16(result, offset, output_search_range); | 994 offset = StoreU16(result, offset, output_search_range); |
| 926 offset = StoreU16(result, offset, max_pow2); | 995 offset = StoreU16(result, offset, max_pow2); |
| 927 offset = StoreU16(result, offset, (num_tables << 4) - output_search_range); | 996 offset = StoreU16(result, offset, (num_tables << 4) - output_search_range); |
| 997 |
| 998 // sort tags in the table directory in ascending alphabetical order |
| 999 std::vector<Table> sorted_tables(tables); |
| 1000 std::sort(sorted_tables.begin(), sorted_tables.end()); |
| 1001 |
| 928 for (uint16_t i = 0; i < num_tables; ++i) { | 1002 for (uint16_t i = 0; i < num_tables; ++i) { |
| 929 const Table* table = &tables.at(i); | 1003 const Table* table = &sorted_tables.at(i); |
| 930 offset = StoreU32(result, offset, table->tag); | 1004 offset = StoreU32(result, offset, table->tag); |
| 931 offset = StoreU32(result, offset, 0); // checksum, to fill in later | 1005 offset = StoreU32(result, offset, 0); // checksum, to fill in later |
| 932 offset = StoreU32(result, offset, table->dst_offset); | 1006 offset = StoreU32(result, offset, table->dst_offset); |
| 933 offset = StoreU32(result, offset, table->dst_length); | 1007 offset = StoreU32(result, offset, table->dst_length); |
| 934 } | 1008 } |
| 935 std::vector<uint8_t> uncompressed_buf; | 1009 std::vector<uint8_t> uncompressed_buf; |
| 936 const uint8_t* transform_buf = NULL; | 1010 const uint8_t* transform_buf = NULL; |
| 937 uint64_t total_size = 0; | 1011 uint64_t total_size = 0; |
| 938 | 1012 |
| 939 for (uint16_t i = 0; i < num_tables; ++i) { | 1013 for (uint16_t i = 0; i < num_tables; ++i) { |
| 940 total_size += tables.at(i).transform_length; | 1014 total_size += tables.at(i).transform_length; |
| 941 if (total_size > std::numeric_limits<uint32_t>::max()) { | 1015 if (total_size > std::numeric_limits<uint32_t>::max()) { |
| 942 return OTS_FAILURE(); | 1016 return OTS_FAILURE(); |
| 943 } | 1017 } |
| 944 } | 1018 } |
| 945 // Enforce same 30M limit on uncompressed tables as OTS | 1019 // Enforce same 30M limit on uncompressed tables as OTS |
| 946 if (total_size > 30 * 1024 * 1024) { | 1020 if (total_size > 30 * 1024 * 1024) { |
| 947 return OTS_FAILURE(); | 1021 return OTS_FAILURE(); |
| 948 } | 1022 } |
| 949 const size_t total_size_size_t = static_cast<size_t>(total_size); | 1023 const size_t total_size_size_t = static_cast<size_t>(total_size); |
| 950 uncompressed_buf.resize(total_size_size_t); | 1024 uncompressed_buf.resize(total_size_size_t); |
| 951 const uint8_t* src_buf = data + compressed_offset; | 1025 const uint8_t* src_buf = data + compressed_offset; |
| 952 if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t, | 1026 if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t, |
| 953 src_buf, compressed_length)) { | 1027 src_buf, compressed_length)) { |
| 954 return OTS_FAILURE(); | 1028 return OTS_FAILURE_MSG("Failed to uncompress font data"); |
| 955 } | 1029 } |
| 956 transform_buf = &uncompressed_buf[0]; | 1030 transform_buf = &uncompressed_buf[0]; |
| 957 | 1031 |
| 958 for (uint16_t i = 0; i < num_tables; ++i) { | 1032 for (uint16_t i = 0; i < num_tables; ++i) { |
| 959 const Table* table = &tables.at(i); | 1033 const Table* table = &tables.at(i); |
| 960 uint32_t flags = table->flags; | 1034 uint32_t flags = table->flags; |
| 961 size_t transform_length = table->transform_length; | 1035 size_t transform_length = table->transform_length; |
| 962 | 1036 |
| 963 if ((flags & kWoff2FlagsTransform) == 0) { | 1037 if ((flags & kWoff2FlagsTransform) == 0) { |
| 964 if (transform_length != table->dst_length) { | 1038 if (transform_length != table->dst_length) { |
| 965 return OTS_FAILURE(); | 1039 return OTS_FAILURE(); |
| 966 } | 1040 } |
| 967 if (static_cast<uint64_t>(table->dst_offset) + transform_length > | 1041 if (static_cast<uint64_t>(table->dst_offset) + transform_length > |
| 968 result_length) { | 1042 result_length) { |
| 969 return OTS_FAILURE(); | 1043 return OTS_FAILURE(); |
| 970 } | 1044 } |
| 971 std::memcpy(result + table->dst_offset, transform_buf, | 1045 std::memcpy(result + table->dst_offset, transform_buf, |
| 972 transform_length); | 1046 transform_length); |
| 973 } else { | 1047 } else { |
| 974 if (!ReconstructTransformed(tables, table->tag, | 1048 if (!ReconstructTransformed(file, tables, table->tag, |
| 975 transform_buf, transform_length, result, result_length)) { | 1049 transform_buf, transform_length, result, result_length)) { |
| 976 return OTS_FAILURE(); | 1050 return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", CHR(tab
le->tag)); |
| 977 } | 1051 } |
| 978 } | 1052 } |
| 979 | 1053 |
| 980 transform_buf += transform_length; | 1054 transform_buf += transform_length; |
| 981 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) { | 1055 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) { |
| 982 return OTS_FAILURE(); | 1056 return OTS_FAILURE(); |
| 983 } | 1057 } |
| 984 } | 1058 } |
| 985 | 1059 |
| 986 return FixChecksums(tables, result); | 1060 return FixChecksums(sorted_tables, result); |
| 987 } | 1061 } |
| 988 | 1062 |
| 989 } // namespace ots | 1063 } // namespace ots |
| 990 | 1064 |
| 991 #undef TABLE_NAME | 1065 #undef TABLE_NAME |
| OLD | NEW |