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 |