OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 // A parser for the Type 2 Charstring Format. | 5 // A parser for the Type 2 Charstring Format. |
6 // http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf | 6 // http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf |
7 | 7 |
8 #include "cff_type2_charstring.h" | 8 #include "cff_type2_charstring.h" |
9 | 9 |
10 #include <climits> | 10 #include <climits> |
11 #include <cstdio> | 11 #include <cstdio> |
12 #include <cstring> | 12 #include <cstring> |
13 #include <stack> | 13 #include <stack> |
14 #include <string> | 14 #include <string> |
15 #include <utility> | 15 #include <utility> |
16 | 16 |
| 17 #define TABLE_NAME "CFF" |
| 18 |
17 namespace { | 19 namespace { |
18 | 20 |
19 // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical | 21 // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical |
20 // Note #5177. | 22 // Note #5177. |
21 const int32_t kMaxSubrsCount = 65536; | 23 const int32_t kMaxSubrsCount = 65536; |
22 const size_t kMaxCharStringLength = 65535; | 24 const size_t kMaxCharStringLength = 65535; |
23 const size_t kMaxArgumentStack = 48; | 25 const size_t kMaxArgumentStack = 48; |
24 const size_t kMaxNumberOfStemHints = 96; | 26 const size_t kMaxNumberOfStemHints = 96; |
25 const size_t kMaxSubrNesting = 10; | 27 const size_t kMaxSubrNesting = 10; |
26 | 28 |
27 // |dummy_result| should be a huge positive integer so callsubr and callgsubr | 29 // |dummy_result| should be a huge positive integer so callsubr and callgsubr |
28 // will fail with the dummy value. | 30 // will fail with the dummy value. |
29 const int32_t dummy_result = INT_MAX; | 31 const int32_t dummy_result = INT_MAX; |
30 | 32 |
31 bool ExecuteType2CharString(size_t call_depth, | 33 bool ExecuteType2CharString(ots::OpenTypeFile *file, |
| 34 size_t call_depth, |
32 const ots::CFFIndex& global_subrs_index, | 35 const ots::CFFIndex& global_subrs_index, |
33 const ots::CFFIndex& local_subrs_index, | 36 const ots::CFFIndex& local_subrs_index, |
34 ots::Buffer *cff_table, | 37 ots::Buffer *cff_table, |
35 ots::Buffer *char_string, | 38 ots::Buffer *char_string, |
36 std::stack<int32_t> *argument_stack, | 39 std::stack<int32_t> *argument_stack, |
37 bool *out_found_endchar, | 40 bool *out_found_endchar, |
38 bool *out_found_width, | 41 bool *out_found_width, |
39 size_t *in_out_num_stems); | 42 size_t *in_out_num_stems); |
40 | 43 |
| 44 #ifdef DUMP_T2CHARSTRING |
| 45 // Converts |op| to a string and returns it. |
| 46 const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) { |
| 47 switch (op) { |
| 48 case ots::kHStem: |
| 49 return "HStem"; |
| 50 case ots::kVStem: |
| 51 return "VStem"; |
| 52 case ots::kVMoveTo: |
| 53 return "VMoveTo"; |
| 54 case ots::kRLineTo: |
| 55 return "RLineTo"; |
| 56 case ots::kHLineTo: |
| 57 return "HLineTo"; |
| 58 case ots::kVLineTo: |
| 59 return "VLineTo"; |
| 60 case ots::kRRCurveTo: |
| 61 return "RRCurveTo"; |
| 62 case ots::kCallSubr: |
| 63 return "CallSubr"; |
| 64 case ots::kReturn: |
| 65 return "Return"; |
| 66 case ots::kEndChar: |
| 67 return "EndChar"; |
| 68 case ots::kHStemHm: |
| 69 return "HStemHm"; |
| 70 case ots::kHintMask: |
| 71 return "HintMask"; |
| 72 case ots::kCntrMask: |
| 73 return "CntrMask"; |
| 74 case ots::kRMoveTo: |
| 75 return "RMoveTo"; |
| 76 case ots::kHMoveTo: |
| 77 return "HMoveTo"; |
| 78 case ots::kVStemHm: |
| 79 return "VStemHm"; |
| 80 case ots::kRCurveLine: |
| 81 return "RCurveLine"; |
| 82 case ots::kRLineCurve: |
| 83 return "RLineCurve"; |
| 84 case ots::kVVCurveTo: |
| 85 return "VVCurveTo"; |
| 86 case ots::kHHCurveTo: |
| 87 return "HHCurveTo"; |
| 88 case ots::kCallGSubr: |
| 89 return "CallGSubr"; |
| 90 case ots::kVHCurveTo: |
| 91 return "VHCurveTo"; |
| 92 case ots::kHVCurveTo: |
| 93 return "HVCurveTo"; |
| 94 case ots::kDotSection: |
| 95 return "DotSection"; |
| 96 case ots::kAnd: |
| 97 return "And"; |
| 98 case ots::kOr: |
| 99 return "Or"; |
| 100 case ots::kNot: |
| 101 return "Not"; |
| 102 case ots::kAbs: |
| 103 return "Abs"; |
| 104 case ots::kAdd: |
| 105 return "Add"; |
| 106 case ots::kSub: |
| 107 return "Sub"; |
| 108 case ots::kDiv: |
| 109 return "Div"; |
| 110 case ots::kNeg: |
| 111 return "Neg"; |
| 112 case ots::kEq: |
| 113 return "Eq"; |
| 114 case ots::kDrop: |
| 115 return "Drop"; |
| 116 case ots::kPut: |
| 117 return "Put"; |
| 118 case ots::kGet: |
| 119 return "Get"; |
| 120 case ots::kIfElse: |
| 121 return "IfElse"; |
| 122 case ots::kRandom: |
| 123 return "Random"; |
| 124 case ots::kMul: |
| 125 return "Mul"; |
| 126 case ots::kSqrt: |
| 127 return "Sqrt"; |
| 128 case ots::kDup: |
| 129 return "Dup"; |
| 130 case ots::kExch: |
| 131 return "Exch"; |
| 132 case ots::kIndex: |
| 133 return "Index"; |
| 134 case ots::kRoll: |
| 135 return "Roll"; |
| 136 case ots::kHFlex: |
| 137 return "HFlex"; |
| 138 case ots::kFlex: |
| 139 return "Flex"; |
| 140 case ots::kHFlex1: |
| 141 return "HFlex1"; |
| 142 case ots::kFlex1: |
| 143 return "Flex1"; |
| 144 } |
| 145 |
| 146 return "UNKNOWN"; |
| 147 } |
| 148 #endif |
| 149 |
41 // Read one or more bytes from the |char_string| buffer and stores the number | 150 // Read one or more bytes from the |char_string| buffer and stores the number |
42 // read on |out_number|. If the number read is an operator (ex 'vstem'), sets | 151 // read on |out_number|. If the number read is an operator (ex 'vstem'), sets |
43 // true on |out_is_operator|. Returns true if the function read a number. | 152 // true on |out_is_operator|. Returns true if the function read a number. |
44 bool ReadNextNumberFromType2CharString(ots::Buffer *char_string, | 153 bool ReadNextNumberFromType2CharString(ots::Buffer *char_string, |
45 int32_t *out_number, | 154 int32_t *out_number, |
46 bool *out_is_operator) { | 155 bool *out_is_operator) { |
47 uint8_t v = 0; | 156 uint8_t v = 0; |
48 if (!char_string->ReadU8(&v)) { | 157 if (!char_string->ReadU8(&v)) { |
49 return OTS_FAILURE(); | 158 return OTS_FAILURE(); |
50 } | 159 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 return OTS_FAILURE(); | 218 return OTS_FAILURE(); |
110 } | 219 } |
111 | 220 |
112 return true; | 221 return true; |
113 } | 222 } |
114 | 223 |
115 // Executes |op| and updates |argument_stack|. Returns true if the execution | 224 // Executes |op| and updates |argument_stack|. Returns true if the execution |
116 // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively | 225 // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively |
117 // calls ExecuteType2CharString() function. The arguments other than |op| and | 226 // calls ExecuteType2CharString() function. The arguments other than |op| and |
118 // |argument_stack| are passed for that reason. | 227 // |argument_stack| are passed for that reason. |
119 bool ExecuteType2CharStringOperator(int32_t op, | 228 bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file, |
| 229 int32_t op, |
120 size_t call_depth, | 230 size_t call_depth, |
121 const ots::CFFIndex& global_subrs_index, | 231 const ots::CFFIndex& global_subrs_index, |
122 const ots::CFFIndex& local_subrs_index, | 232 const ots::CFFIndex& local_subrs_index, |
123 ots::Buffer *cff_table, | 233 ots::Buffer *cff_table, |
124 ots::Buffer *char_string, | 234 ots::Buffer *char_string, |
125 std::stack<int32_t> *argument_stack, | 235 std::stack<int32_t> *argument_stack, |
126 bool *out_found_endchar, | 236 bool *out_found_endchar, |
127 bool *in_out_found_width, | 237 bool *in_out_found_width, |
128 size_t *in_out_num_stems) { | 238 size_t *in_out_num_stems) { |
129 const size_t stack_size = argument_stack->size(); | 239 const size_t stack_size = argument_stack->size(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 if (length > kMaxCharStringLength) { | 283 if (length > kMaxCharStringLength) { |
174 return OTS_FAILURE(); | 284 return OTS_FAILURE(); |
175 } | 285 } |
176 const size_t offset = subrs_index.offsets[subr_number]; | 286 const size_t offset = subrs_index.offsets[subr_number]; |
177 cff_table->set_offset(offset); | 287 cff_table->set_offset(offset); |
178 if (!cff_table->Skip(length)) { | 288 if (!cff_table->Skip(length)) { |
179 return OTS_FAILURE(); | 289 return OTS_FAILURE(); |
180 } | 290 } |
181 ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length); | 291 ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length); |
182 | 292 |
183 return ExecuteType2CharString(call_depth + 1, | 293 return ExecuteType2CharString(file, |
| 294 call_depth + 1, |
184 global_subrs_index, | 295 global_subrs_index, |
185 local_subrs_index, | 296 local_subrs_index, |
186 cff_table, | 297 cff_table, |
187 &char_string_to_jump, | 298 &char_string_to_jump, |
188 argument_stack, | 299 argument_stack, |
189 out_found_endchar, | 300 out_found_endchar, |
190 in_out_found_width, | 301 in_out_found_width, |
191 in_out_num_stems); | 302 in_out_num_stems); |
192 } | 303 } |
193 | 304 |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 } else if ((stack_size >= 9) && | 526 } else if ((stack_size >= 9) && |
416 ((stack_size - 9) % 8) == 0) { | 527 ((stack_size - 9) % 8) == 0) { |
417 // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? | 528 // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? |
418 successful = true; | 529 successful = true; |
419 } | 530 } |
420 while (!argument_stack->empty()) | 531 while (!argument_stack->empty()) |
421 argument_stack->pop(); | 532 argument_stack->pop(); |
422 return successful ? true : OTS_FAILURE(); | 533 return successful ? true : OTS_FAILURE(); |
423 } | 534 } |
424 | 535 |
| 536 case ots::kDotSection: |
| 537 // Deprecated operator but harmless, we probably should drop it some how. |
| 538 if (stack_size != 0) { |
| 539 return OTS_FAILURE(); |
| 540 } |
| 541 return true; |
| 542 |
425 case ots::kAnd: | 543 case ots::kAnd: |
426 case ots::kOr: | 544 case ots::kOr: |
427 case ots::kEq: | 545 case ots::kEq: |
428 case ots::kAdd: | 546 case ots::kAdd: |
429 case ots::kSub: | 547 case ots::kSub: |
430 if (stack_size < 2) { | 548 if (stack_size < 2) { |
431 return OTS_FAILURE(); | 549 return OTS_FAILURE(); |
432 } | 550 } |
433 argument_stack->pop(); | 551 argument_stack->pop(); |
434 argument_stack->pop(); | 552 argument_stack->pop(); |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 return OTS_FAILURE(); | 706 return OTS_FAILURE(); |
589 } | 707 } |
590 if (stack_size != 11) { | 708 if (stack_size != 11) { |
591 return OTS_FAILURE(); | 709 return OTS_FAILURE(); |
592 } | 710 } |
593 while (!argument_stack->empty()) | 711 while (!argument_stack->empty()) |
594 argument_stack->pop(); | 712 argument_stack->pop(); |
595 return true; | 713 return true; |
596 } | 714 } |
597 | 715 |
598 OTS_WARNING("Undefined operator: %d (0x%x)", op, op); | 716 return OTS_FAILURE_MSG("Undefined operator: %d (0x%x)", op, op); |
599 return OTS_FAILURE(); | |
600 } | 717 } |
601 | 718 |
602 // Executes |char_string| and updates |argument_stack|. | 719 // Executes |char_string| and updates |argument_stack|. |
603 // | 720 // |
604 // call_depth: The current call depth. Initial value is zero. | 721 // call_depth: The current call depth. Initial value is zero. |
605 // global_subrs_index: Global subroutines. | 722 // global_subrs_index: Global subroutines. |
606 // local_subrs_index: Local subroutines for the current glyph. | 723 // local_subrs_index: Local subroutines for the current glyph. |
607 // cff_table: A whole CFF table which contains all global and local subroutines. | 724 // cff_table: A whole CFF table which contains all global and local subroutines. |
608 // char_string: A charstring we'll execute. |char_string| can be a main routine | 725 // char_string: A charstring we'll execute. |char_string| can be a main routine |
609 // in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr. | 726 // in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr. |
610 // argument_stack: The stack which an operator in |char_string| operates. | 727 // argument_stack: The stack which an operator in |char_string| operates. |
611 // out_found_endchar: true is set if |char_string| contains 'endchar'. | 728 // out_found_endchar: true is set if |char_string| contains 'endchar'. |
612 // in_out_found_width: true is set if |char_string| contains 'width' byte (which | 729 // in_out_found_width: true is set if |char_string| contains 'width' byte (which |
613 // is 0 or 1 byte.) | 730 // is 0 or 1 byte.) |
614 // in_out_num_stems: total number of hstems and vstems processed so far. | 731 // in_out_num_stems: total number of hstems and vstems processed so far. |
615 bool ExecuteType2CharString(size_t call_depth, | 732 bool ExecuteType2CharString(ots::OpenTypeFile *file, |
| 733 size_t call_depth, |
616 const ots::CFFIndex& global_subrs_index, | 734 const ots::CFFIndex& global_subrs_index, |
617 const ots::CFFIndex& local_subrs_index, | 735 const ots::CFFIndex& local_subrs_index, |
618 ots::Buffer *cff_table, | 736 ots::Buffer *cff_table, |
619 ots::Buffer *char_string, | 737 ots::Buffer *char_string, |
620 std::stack<int32_t> *argument_stack, | 738 std::stack<int32_t> *argument_stack, |
621 bool *out_found_endchar, | 739 bool *out_found_endchar, |
622 bool *in_out_found_width, | 740 bool *in_out_found_width, |
623 size_t *in_out_num_stems) { | 741 size_t *in_out_num_stems) { |
624 if (call_depth > kMaxSubrNesting) { | 742 if (call_depth > kMaxSubrNesting) { |
625 return OTS_FAILURE(); | 743 return OTS_FAILURE(); |
626 } | 744 } |
627 *out_found_endchar = false; | 745 *out_found_endchar = false; |
628 | 746 |
629 const size_t length = char_string->length(); | 747 const size_t length = char_string->length(); |
630 while (char_string->offset() < length) { | 748 while (char_string->offset() < length) { |
631 int32_t operator_or_operand = 0; | 749 int32_t operator_or_operand = 0; |
632 bool is_operator = false; | 750 bool is_operator = false; |
633 if (!ReadNextNumberFromType2CharString(char_string, | 751 if (!ReadNextNumberFromType2CharString(char_string, |
634 &operator_or_operand, | 752 &operator_or_operand, |
635 &is_operator)) { | 753 &is_operator)) { |
636 return OTS_FAILURE(); | 754 return OTS_FAILURE(); |
637 } | 755 } |
638 | 756 |
| 757 #ifdef DUMP_T2CHARSTRING |
639 /* | 758 /* |
640 You can dump all operators and operands (except mask bytes for hintmask | 759 You can dump all operators and operands (except mask bytes for hintmask |
641 and cntrmask) by the following code: | 760 and cntrmask) by the following code: |
| 761 */ |
642 | 762 |
643 if (!is_operator) { | 763 if (!is_operator) { |
644 std::fprintf(stderr, "#%d# ", operator_or_operand); | 764 std::fprintf(stderr, "#%d# ", operator_or_operand); |
645 } else { | 765 } else { |
646 std::fprintf(stderr, "#%s#\n", | 766 std::fprintf(stderr, "#%s#\n", |
647 Type2CharStringOperatorToString( | 767 Type2CharStringOperatorToString( |
648 Type2CharStringOperator(operator_or_operand)), | 768 ots::Type2CharStringOperator(operator_or_operand)) |
649 operator_or_operand); | 769 ); |
650 } | 770 } |
651 */ | 771 #endif |
652 | 772 |
653 if (!is_operator) { | 773 if (!is_operator) { |
654 argument_stack->push(operator_or_operand); | 774 argument_stack->push(operator_or_operand); |
655 if (argument_stack->size() > kMaxArgumentStack) { | 775 if (argument_stack->size() > kMaxArgumentStack) { |
656 return OTS_FAILURE(); | 776 return OTS_FAILURE(); |
657 } | 777 } |
658 continue; | 778 continue; |
659 } | 779 } |
660 | 780 |
661 // An operator is found. Execute it. | 781 // An operator is found. Execute it. |
662 if (!ExecuteType2CharStringOperator(operator_or_operand, | 782 if (!ExecuteType2CharStringOperator(file, |
| 783 operator_or_operand, |
663 call_depth, | 784 call_depth, |
664 global_subrs_index, | 785 global_subrs_index, |
665 local_subrs_index, | 786 local_subrs_index, |
666 cff_table, | 787 cff_table, |
667 char_string, | 788 char_string, |
668 argument_stack, | 789 argument_stack, |
669 out_found_endchar, | 790 out_found_endchar, |
670 in_out_found_width, | 791 in_out_found_width, |
671 in_out_num_stems)) { | 792 in_out_num_stems)) { |
672 return OTS_FAILURE(); | 793 return OTS_FAILURE(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 } | 838 } |
718 | 839 |
719 return true; | 840 return true; |
720 } | 841 } |
721 | 842 |
722 } // namespace | 843 } // namespace |
723 | 844 |
724 namespace ots { | 845 namespace ots { |
725 | 846 |
726 bool ValidateType2CharStringIndex( | 847 bool ValidateType2CharStringIndex( |
| 848 ots::OpenTypeFile *file, |
727 const CFFIndex& char_strings_index, | 849 const CFFIndex& char_strings_index, |
728 const CFFIndex& global_subrs_index, | 850 const CFFIndex& global_subrs_index, |
729 const std::map<uint16_t, uint8_t> &fd_select, | 851 const std::map<uint16_t, uint8_t> &fd_select, |
730 const std::vector<CFFIndex *> &local_subrs_per_font, | 852 const std::vector<CFFIndex *> &local_subrs_per_font, |
731 const CFFIndex *local_subrs, | 853 const CFFIndex *local_subrs, |
732 Buffer* cff_table) { | 854 Buffer* cff_table) { |
733 const uint16_t num_offsets = | 855 const uint16_t num_offsets = |
734 static_cast<uint16_t>(char_strings_index.offsets.size()); | 856 static_cast<uint16_t>(char_strings_index.offsets.size()); |
735 if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) { | 857 if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) { |
736 return OTS_FAILURE(); // no charstring. | 858 return OTS_FAILURE(); // no charstring. |
(...skipping 29 matching lines...) Expand all Loading... |
766 CFFIndex default_empty_subrs; | 888 CFFIndex default_empty_subrs; |
767 if (!local_subrs_to_use){ | 889 if (!local_subrs_to_use){ |
768 local_subrs_to_use = &default_empty_subrs; | 890 local_subrs_to_use = &default_empty_subrs; |
769 } | 891 } |
770 | 892 |
771 // Check a charstring for the |i|-th glyph. | 893 // Check a charstring for the |i|-th glyph. |
772 std::stack<int32_t> argument_stack; | 894 std::stack<int32_t> argument_stack; |
773 bool found_endchar = false; | 895 bool found_endchar = false; |
774 bool found_width = false; | 896 bool found_width = false; |
775 size_t num_stems = 0; | 897 size_t num_stems = 0; |
776 if (!ExecuteType2CharString(0 /* initial call_depth is zero */, | 898 if (!ExecuteType2CharString(file, |
| 899 0 /* initial call_depth is zero */, |
777 global_subrs_index, *local_subrs_to_use, | 900 global_subrs_index, *local_subrs_to_use, |
778 cff_table, &char_string, &argument_stack, | 901 cff_table, &char_string, &argument_stack, |
779 &found_endchar, &found_width, &num_stems)) { | 902 &found_endchar, &found_width, &num_stems)) { |
780 return OTS_FAILURE(); | 903 return OTS_FAILURE(); |
781 } | 904 } |
782 if (!found_endchar) { | 905 if (!found_endchar) { |
783 return OTS_FAILURE(); | 906 return OTS_FAILURE(); |
784 } | 907 } |
785 } | 908 } |
786 return true; | 909 return true; |
787 } | 910 } |
788 | 911 |
789 } // namespace ots | 912 } // namespace ots |
| 913 |
| 914 #undef TABLE_NAME |
OLD | NEW |