| Index: src/cff_type2_charstring.cc
|
| ===================================================================
|
| --- src/cff_type2_charstring.cc (revision 34)
|
| +++ src/cff_type2_charstring.cc (working copy)
|
| @@ -7,73 +7,27 @@
|
|
|
| #include "cff_type2_charstring.h"
|
|
|
| +#include <climits>
|
| #include <cstdio>
|
| #include <cstring>
|
| -#include <limits>
|
| #include <stack>
|
| #include <string>
|
| #include <utility>
|
|
|
| namespace {
|
|
|
| -// The list of Operators. See Appendix. A in Adobe Technical Note #5177.
|
| -enum Type2CharStringOperator {
|
| - kHStem = 1,
|
| - kVStem = 3,
|
| - kVMoveTo = 4,
|
| - kRLineTo = 5,
|
| - kHLineTo = 6,
|
| - kVLineTo = 7,
|
| - kRRCurveTo = 8,
|
| - kCallSubr = 10,
|
| - kReturn = 11,
|
| - kEndChar = 14,
|
| - kHStemHm = 18,
|
| - kHintMask = 19,
|
| - kCntrMask = 20,
|
| - kRMoveTo = 21,
|
| - kHMoveTo = 22,
|
| - kVStemHm = 23,
|
| - kRCurveLine = 24,
|
| - kRLineCurve = 25,
|
| - kVVCurveTo = 26,
|
| - kHHCurveTo = 27,
|
| - kCallGSubr = 29,
|
| - kVHCurveTo = 30,
|
| - kHVCurveTo = 31,
|
| - kAnd = (12 << 8) + 3,
|
| - kOr = (12 << 8) + 4,
|
| - kNot = (12 << 8) + 5,
|
| - kAbs = (12 << 8) + 9,
|
| - kAdd = (12 << 8) + 10,
|
| - kSub = (12 << 8) + 11,
|
| - kDiv = (12 << 8) + 12,
|
| - kNeg = (12 << 8) + 14,
|
| - kEq = (12 << 8) + 15,
|
| - kDrop = (12 << 8) + 18,
|
| - kPut = (12 << 8) + 20,
|
| - kGet = (12 << 8) + 21,
|
| - kIfElse = (12 << 8) + 22,
|
| - kRandom = (12 << 8) + 23,
|
| - kMul = (12 << 8) + 24,
|
| - kSqrt = (12 << 8) + 26,
|
| - kDup = (12 << 8) + 27,
|
| - kExch = (12 << 8) + 28,
|
| - kIndex = (12 << 8) + 29,
|
| - kRoll = (12 << 8) + 30,
|
| - kHFlex = (12 << 8) + 34,
|
| - kFlex = (12 << 8) + 35,
|
| - kHFlex1 = (12 << 8) + 36,
|
| - kFlex1 = (12 << 8) + 37,
|
| -};
|
| -
|
| // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical
|
| // Note #5177.
|
| +const int32_t kMaxSubrsCount = 65536;
|
| const size_t kMaxCharStringLength = 65535;
|
| const size_t kMaxArgumentStack = 48;
|
| const size_t kMaxNumberOfStemHints = 96;
|
| const size_t kMaxSubrNesting = 10;
|
|
|
| +// |dummy_result| should be a huge positive integer so callsubr and callgsubr
|
| +// will fail with the dummy value.
|
| +const int32_t dummy_result = INT_MAX;
|
| +
|
| bool ExecuteType2CharString(size_t call_depth,
|
| const ots::CFFIndex& global_subrs_index,
|
| const ots::CFFIndex& local_subrs_index,
|
| @@ -85,101 +39,101 @@
|
| size_t *in_out_num_stems);
|
|
|
| // Converts |op| to a string and returns it.
|
| -const char *Type2CharStringOperatorToString(Type2CharStringOperator op) {
|
| +const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) {
|
| switch (op) {
|
| - case kHStem:
|
| + case ots::kHStem:
|
| return "HStem";
|
| - case kVStem:
|
| + case ots::kVStem:
|
| return "VStem";
|
| - case kVMoveTo:
|
| + case ots::kVMoveTo:
|
| return "VMoveTo";
|
| - case kRLineTo:
|
| + case ots::kRLineTo:
|
| return "RLineTo";
|
| - case kHLineTo:
|
| + case ots::kHLineTo:
|
| return "HLineTo";
|
| - case kVLineTo:
|
| + case ots::kVLineTo:
|
| return "VLineTo";
|
| - case kRRCurveTo:
|
| + case ots::kRRCurveTo:
|
| return "RRCurveTo";
|
| - case kCallSubr:
|
| + case ots::kCallSubr:
|
| return "CallSubr";
|
| - case kReturn:
|
| + case ots::kReturn:
|
| return "Return";
|
| - case kEndChar:
|
| + case ots::kEndChar:
|
| return "EndChar";
|
| - case kHStemHm:
|
| + case ots::kHStemHm:
|
| return "HStemHm";
|
| - case kHintMask:
|
| + case ots::kHintMask:
|
| return "HintMask";
|
| - case kCntrMask:
|
| + case ots::kCntrMask:
|
| return "CntrMask";
|
| - case kRMoveTo:
|
| + case ots::kRMoveTo:
|
| return "RMoveTo";
|
| - case kHMoveTo:
|
| + case ots::kHMoveTo:
|
| return "HMoveTo";
|
| - case kVStemHm:
|
| + case ots::kVStemHm:
|
| return "VStemHm";
|
| - case kRCurveLine:
|
| + case ots::kRCurveLine:
|
| return "RCurveLine";
|
| - case kRLineCurve:
|
| + case ots::kRLineCurve:
|
| return "RLineCurve";
|
| - case kVVCurveTo:
|
| + case ots::kVVCurveTo:
|
| return "VVCurveTo";
|
| - case kHHCurveTo:
|
| + case ots::kHHCurveTo:
|
| return "HHCurveTo";
|
| - case kCallGSubr:
|
| + case ots::kCallGSubr:
|
| return "CallGSubr";
|
| - case kVHCurveTo:
|
| + case ots::kVHCurveTo:
|
| return "VHCurveTo";
|
| - case kHVCurveTo:
|
| + case ots::kHVCurveTo:
|
| return "HVCurveTo";
|
| - case kAnd:
|
| + case ots::kAnd:
|
| return "And";
|
| - case kOr:
|
| + case ots::kOr:
|
| return "Or";
|
| - case kNot:
|
| + case ots::kNot:
|
| return "Not";
|
| - case kAbs:
|
| + case ots::kAbs:
|
| return "Abs";
|
| - case kAdd:
|
| + case ots::kAdd:
|
| return "Add";
|
| - case kSub:
|
| + case ots::kSub:
|
| return "Sub";
|
| - case kDiv:
|
| + case ots::kDiv:
|
| return "Div";
|
| - case kNeg:
|
| + case ots::kNeg:
|
| return "Neg";
|
| - case kEq:
|
| + case ots::kEq:
|
| return "Eq";
|
| - case kDrop:
|
| + case ots::kDrop:
|
| return "Drop";
|
| - case kPut:
|
| + case ots::kPut:
|
| return "Put";
|
| - case kGet:
|
| + case ots::kGet:
|
| return "Get";
|
| - case kIfElse:
|
| + case ots::kIfElse:
|
| return "IfElse";
|
| - case kRandom:
|
| + case ots::kRandom:
|
| return "Random";
|
| - case kMul:
|
| + case ots::kMul:
|
| return "Mul";
|
| - case kSqrt:
|
| + case ots::kSqrt:
|
| return "Sqrt";
|
| - case kDup:
|
| + case ots::kDup:
|
| return "Dup";
|
| - case kExch:
|
| + case ots::kExch:
|
| return "Exch";
|
| - case kIndex:
|
| + case ots::kIndex:
|
| return "Index";
|
| - case kRoll:
|
| + case ots::kRoll:
|
| return "Roll";
|
| - case kHFlex:
|
| + case ots::kHFlex:
|
| return "HFlex";
|
| - case kFlex:
|
| + case ots::kFlex:
|
| return "Flex";
|
| - case kHFlex1:
|
| + case ots::kHFlex1:
|
| return "HFlex1";
|
| - case kFlex1:
|
| + case ots::kFlex1:
|
| return "Flex1";
|
| }
|
|
|
| @@ -246,16 +200,13 @@
|
| *out_number = -((static_cast<int32_t>(v) - 251) * 256) -
|
| static_cast<int32_t>(w) - 108;
|
| } else if (v == 255) {
|
| - uint32_t result = 0;
|
| - for (size_t i = 0; i < 4; ++i) {
|
| - if (!char_string->ReadU8(&v)) {
|
| - return OTS_FAILURE();
|
| - }
|
| - result = (result << 8) + v;
|
| - }
|
| - // TODO(yusukes): |result| should be treated as 16.16 fixed-point number
|
| + // TODO(yusukes): We should not skip the 4 bytes. Note that when v is 255,
|
| + // we should treat the following 4-bytes as a 16.16 fixed-point number
|
| // rather than 32bit signed int.
|
| - *out_number = static_cast<int32_t>(result);
|
| + if (!char_string->Skip(4)) {
|
| + return OTS_FAILURE();
|
| + }
|
| + *out_number = dummy_result;
|
| } else {
|
| return OTS_FAILURE();
|
| }
|
| @@ -277,16 +228,13 @@
|
| bool *out_found_endchar,
|
| bool *in_out_found_width,
|
| size_t *in_out_num_stems) {
|
| - // |dummy_result| should be a huge positive integer so callsubr and callgsubr
|
| - // will fail with the dummy value.
|
| - const int32_t dummy_result = std::numeric_limits<int>::max();
|
| const size_t stack_size = argument_stack->size();
|
|
|
| switch (op) {
|
| - case kCallSubr:
|
| - case kCallGSubr: {
|
| + case ots::kCallSubr:
|
| + case ots::kCallGSubr: {
|
| const ots::CFFIndex& subrs_index =
|
| - (op == kCallSubr ? local_subrs_index : global_subrs_index);
|
| + (op == ots::kCallSubr ? local_subrs_index : global_subrs_index);
|
|
|
| if (stack_size < 1) {
|
| return OTS_FAILURE();
|
| @@ -314,7 +262,10 @@
|
| if (subr_number < 0) {
|
| return OTS_FAILURE();
|
| }
|
| - if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number)) {
|
| + if (subr_number >= kMaxSubrsCount) {
|
| + return OTS_FAILURE();
|
| + }
|
| + if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number + 1)) {
|
| return OTS_FAILURE(); // The number is out-of-bounds.
|
| }
|
|
|
| @@ -342,18 +293,18 @@
|
| in_out_num_stems);
|
| }
|
|
|
| - case kReturn:
|
| + case ots::kReturn:
|
| return true;
|
|
|
| - case kEndChar:
|
| + case ots::kEndChar:
|
| *out_found_endchar = true;
|
| *in_out_found_width = true; // just in case.
|
| return true;
|
|
|
| - case kHStem:
|
| - case kVStem:
|
| - case kHStemHm:
|
| - case kVStemHm: {
|
| + case ots::kHStem:
|
| + case ots::kVStem:
|
| + case ots::kHStemHm:
|
| + case ots::kVStemHm: {
|
| bool successful = false;
|
| if (stack_size < 2) {
|
| return OTS_FAILURE();
|
| @@ -375,7 +326,7 @@
|
| return successful ? true : OTS_FAILURE();
|
| }
|
|
|
| - case kRMoveTo: {
|
| + case ots::kRMoveTo: {
|
| bool successful = false;
|
| if (stack_size == 2) {
|
| successful = true;
|
| @@ -388,8 +339,8 @@
|
| return successful ? true : OTS_FAILURE();
|
| }
|
|
|
| - case kVMoveTo:
|
| - case kHMoveTo: {
|
| + case ots::kVMoveTo:
|
| + case ots::kHMoveTo: {
|
| bool successful = false;
|
| if (stack_size == 1) {
|
| successful = true;
|
| @@ -402,8 +353,8 @@
|
| return successful ? true : OTS_FAILURE();
|
| }
|
|
|
| - case kHintMask:
|
| - case kCntrMask: {
|
| + case ots::kHintMask:
|
| + case ots::kCntrMask: {
|
| bool successful = false;
|
| if (stack_size == 0) {
|
| successful = true;
|
| @@ -437,7 +388,7 @@
|
| return true;
|
| }
|
|
|
| - case kRLineTo:
|
| + case ots::kRLineTo:
|
| if (!(*in_out_found_width)) {
|
| // The first stack-clearing operator should be one of hstem, hstemhm,
|
| // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or
|
| @@ -454,8 +405,8 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kHLineTo:
|
| - case kVLineTo:
|
| + case ots::kHLineTo:
|
| + case ots::kVLineTo:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -466,7 +417,7 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kRRCurveTo:
|
| + case ots::kRRCurveTo:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -480,7 +431,7 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kRCurveLine:
|
| + case ots::kRCurveLine:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -494,7 +445,7 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kRLineCurve:
|
| + case ots::kRLineCurve:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -508,7 +459,7 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kVVCurveTo:
|
| + case ots::kVVCurveTo:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -523,7 +474,7 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kHHCurveTo: {
|
| + case ots::kHHCurveTo: {
|
| bool successful = false;
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| @@ -543,8 +494,8 @@
|
| return successful ? true : OTS_FAILURE();
|
| }
|
|
|
| - case kVHCurveTo:
|
| - case kHVCurveTo: {
|
| + case ots::kVHCurveTo:
|
| + case ots::kHVCurveTo: {
|
| bool successful = false;
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| @@ -573,11 +524,11 @@
|
| return successful ? true : OTS_FAILURE();
|
| }
|
|
|
| - case kAnd:
|
| - case kOr:
|
| - case kEq:
|
| - case kAdd:
|
| - case kSub:
|
| + case ots::kAnd:
|
| + case ots::kOr:
|
| + case ots::kEq:
|
| + case ots::kAdd:
|
| + case ots::kSub:
|
| if (stack_size < 2) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -588,9 +539,9 @@
|
| // arithmetic and conditional operations.
|
| return true;
|
|
|
| - case kNot:
|
| - case kAbs:
|
| - case kNeg:
|
| + case ots::kNot:
|
| + case ots::kAbs:
|
| + case ots::kNeg:
|
| if (stack_size < 1) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -600,45 +551,46 @@
|
| // arithmetic and conditional operations.
|
| return true;
|
|
|
| - case kDiv:
|
| + case ots::kDiv:
|
| // TODO(yusukes): Should detect div-by-zero errors.
|
| - if (stack_size < 1) {
|
| + if (stack_size < 2) {
|
| return OTS_FAILURE();
|
| }
|
| argument_stack->pop();
|
| + argument_stack->pop();
|
| argument_stack->push(dummy_result);
|
| // TODO(yusukes): Implement this. We should push a real value for all
|
| // arithmetic and conditional operations.
|
| return true;
|
|
|
| - case kDrop:
|
| + case ots::kDrop:
|
| if (stack_size < 1) {
|
| return OTS_FAILURE();
|
| }
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kPut:
|
| - case kGet:
|
| - case kIndex:
|
| + case ots::kPut:
|
| + case ots::kGet:
|
| + case ots::kIndex:
|
| // For now, just call OTS_FAILURE since there is no way to check whether the
|
| // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType
|
| // fonts I have (except malicious ones!) use the operators.
|
| // TODO(yusukes): Implement them in a secure way.
|
| return OTS_FAILURE();
|
|
|
| - case kRoll:
|
| + case ots::kRoll:
|
| // Likewise, just call OTS_FAILURE for kRoll since there is no way to check
|
| // whether |N| is smaller than the current stack depth or not.
|
| // TODO(yusukes): Implement them in a secure way.
|
| return OTS_FAILURE();
|
|
|
| - case kRandom:
|
| + case ots::kRandom:
|
| // For now, we don't handle the 'random' operator since the operator makes
|
| // it hard to analyze hinting code statically.
|
| return OTS_FAILURE();
|
|
|
| - case kIfElse:
|
| + case ots::kIfElse:
|
| if (stack_size < 4) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -651,7 +603,7 @@
|
| // arithmetic and conditional operations.
|
| return true;
|
|
|
| - case kMul:
|
| + case ots::kMul:
|
| // TODO(yusukes): Should detect overflows.
|
| if (stack_size < 2) {
|
| return OTS_FAILURE();
|
| @@ -663,7 +615,7 @@
|
| // arithmetic and conditional operations.
|
| return true;
|
|
|
| - case kSqrt:
|
| + case ots::kSqrt:
|
| // TODO(yusukes): Should check if the argument is negative.
|
| if (stack_size < 1) {
|
| return OTS_FAILURE();
|
| @@ -674,7 +626,7 @@
|
| // arithmetic and conditional operations.
|
| return true;
|
|
|
| - case kDup:
|
| + case ots::kDup:
|
| if (stack_size < 1) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -688,7 +640,7 @@
|
| // arithmetic and conditional operations.
|
| return true;
|
|
|
| - case kExch:
|
| + case ots::kExch:
|
| if (stack_size < 2) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -700,7 +652,7 @@
|
| // arithmetic and conditional operations.
|
| return true;
|
|
|
| - case kHFlex:
|
| + case ots::kHFlex:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -711,7 +663,7 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kFlex:
|
| + case ots::kFlex:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -722,7 +674,7 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kHFlex1:
|
| + case ots::kHFlex1:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -733,7 +685,7 @@
|
| argument_stack->pop();
|
| return true;
|
|
|
| - case kFlex1:
|
| + case ots::kFlex1:
|
| if (!(*in_out_found_width)) {
|
| return OTS_FAILURE();
|
| }
|
| @@ -824,7 +776,7 @@
|
| if (*out_found_endchar) {
|
| return true;
|
| }
|
| - if (operator_or_operand == kReturn) {
|
| + if (operator_or_operand == ots::kReturn) {
|
| return true;
|
| }
|
| }
|
| @@ -927,6 +879,9 @@
|
| &found_endchar, &found_width, &num_stems)) {
|
| return OTS_FAILURE();
|
| }
|
| + if (!found_endchar) {
|
| + return OTS_FAILURE();
|
| + }
|
| }
|
| return true;
|
| }
|
|
|