LCOV - code coverage report
Current view: top level - gfx/ots/src - cff_type2_charstring.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 378 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : // A parser for the Type 2 Charstring Format.
       6             : // http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf
       7             : 
       8             : #include "cff_type2_charstring.h"
       9             : 
      10             : #include <climits>
      11             : #include <cstdio>
      12             : #include <cstring>
      13             : #include <stack>
      14             : #include <string>
      15             : #include <utility>
      16             : 
      17             : #define TABLE_NAME "CFF"
      18             : 
      19             : namespace {
      20             : 
      21             : // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical
      22             : // Note #5177.
      23             : const int32_t kMaxSubrsCount = 65536;
      24             : const size_t kMaxCharStringLength = 65535;
      25             : const size_t kMaxArgumentStack = 48;
      26             : const size_t kMaxNumberOfStemHints = 96;
      27             : const size_t kMaxSubrNesting = 10;
      28             : 
      29             : // |dummy_result| should be a huge positive integer so callsubr and callgsubr
      30             : // will fail with the dummy value.
      31             : const int32_t dummy_result = INT_MAX;
      32             : 
      33             : bool ExecuteType2CharString(ots::Font *font,
      34             :                             size_t call_depth,
      35             :                             const ots::CFFIndex& global_subrs_index,
      36             :                             const ots::CFFIndex& local_subrs_index,
      37             :                             ots::Buffer *cff_table,
      38             :                             ots::Buffer *char_string,
      39             :                             std::stack<int32_t> *argument_stack,
      40             :                             bool *out_found_endchar,
      41             :                             bool *out_found_width,
      42             :                             size_t *in_out_num_stems);
      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             : 
     150             : // Read one or more bytes from the |char_string| buffer and stores the number
     151             : // read on |out_number|. If the number read is an operator (ex 'vstem'), sets
     152             : // true on |out_is_operator|. Returns true if the function read a number.
     153           0 : bool ReadNextNumberFromType2CharString(ots::Buffer *char_string,
     154             :                                        int32_t *out_number,
     155             :                                        bool *out_is_operator) {
     156           0 :   uint8_t v = 0;
     157           0 :   if (!char_string->ReadU8(&v)) {
     158           0 :     return OTS_FAILURE();
     159             :   }
     160           0 :   *out_is_operator = false;
     161             : 
     162             :   // The conversion algorithm is described in Adobe Technical Note #5177, page
     163             :   // 13, Table 1.
     164           0 :   if (v <= 11) {
     165           0 :     *out_number = v;
     166           0 :     *out_is_operator = true;
     167           0 :   } else if (v == 12) {
     168           0 :     uint16_t result = (v << 8);
     169           0 :     if (!char_string->ReadU8(&v)) {
     170           0 :       return OTS_FAILURE();
     171             :     }
     172           0 :     result += v;
     173           0 :     *out_number = result;
     174           0 :     *out_is_operator = true;
     175           0 :   } else if (v <= 27) {
     176             :     // Special handling for v==19 and v==20 are implemented in
     177             :     // ExecuteType2CharStringOperator().
     178           0 :     *out_number = v;
     179           0 :     *out_is_operator = true;
     180           0 :   } else if (v == 28) {
     181           0 :     if (!char_string->ReadU8(&v)) {
     182           0 :       return OTS_FAILURE();
     183             :     }
     184           0 :     uint16_t result = (v << 8);
     185           0 :     if (!char_string->ReadU8(&v)) {
     186           0 :       return OTS_FAILURE();
     187             :     }
     188           0 :     result += v;
     189           0 :     *out_number = result;
     190           0 :   } else if (v <= 31) {
     191           0 :     *out_number = v;
     192           0 :     *out_is_operator = true;
     193           0 :   } else if (v <= 246) {
     194           0 :     *out_number = static_cast<int32_t>(v) - 139;
     195           0 :   } else if (v <= 250) {
     196           0 :     uint8_t w = 0;
     197           0 :     if (!char_string->ReadU8(&w)) {
     198           0 :       return OTS_FAILURE();
     199             :     }
     200           0 :     *out_number = ((static_cast<int32_t>(v) - 247) * 256) +
     201           0 :         static_cast<int32_t>(w) + 108;
     202           0 :   } else if (v <= 254) {
     203           0 :     uint8_t w = 0;
     204           0 :     if (!char_string->ReadU8(&w)) {
     205           0 :       return OTS_FAILURE();
     206             :     }
     207           0 :     *out_number = -((static_cast<int32_t>(v) - 251) * 256) -
     208           0 :         static_cast<int32_t>(w) - 108;
     209           0 :   } else if (v == 255) {
     210             :     // TODO(yusukes): We should not skip the 4 bytes. Note that when v is 255,
     211             :     // we should treat the following 4-bytes as a 16.16 fixed-point number
     212             :     // rather than 32bit signed int.
     213           0 :     if (!char_string->Skip(4)) {
     214           0 :       return OTS_FAILURE();
     215             :     }
     216           0 :     *out_number = dummy_result;
     217             :   } else {
     218           0 :     return OTS_FAILURE();
     219             :   }
     220             : 
     221           0 :   return true;
     222             : }
     223             : 
     224             : // Executes |op| and updates |argument_stack|. Returns true if the execution
     225             : // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
     226             : // calls ExecuteType2CharString() function. The arguments other than |op| and
     227             : // |argument_stack| are passed for that reason.
     228           0 : bool ExecuteType2CharStringOperator(ots::Font *font,
     229             :                                     int32_t op,
     230             :                                     size_t call_depth,
     231             :                                     const ots::CFFIndex& global_subrs_index,
     232             :                                     const ots::CFFIndex& local_subrs_index,
     233             :                                     ots::Buffer *cff_table,
     234             :                                     ots::Buffer *char_string,
     235             :                                     std::stack<int32_t> *argument_stack,
     236             :                                     bool *out_found_endchar,
     237             :                                     bool *in_out_found_width,
     238             :                                     size_t *in_out_num_stems) {
     239           0 :   const size_t stack_size = argument_stack->size();
     240             : 
     241           0 :   switch (op) {
     242             :   case ots::kCallSubr:
     243             :   case ots::kCallGSubr: {
     244             :     const ots::CFFIndex& subrs_index =
     245           0 :         (op == ots::kCallSubr ? local_subrs_index : global_subrs_index);
     246             : 
     247           0 :     if (stack_size < 1) {
     248           0 :       return OTS_FAILURE();
     249             :     }
     250           0 :     int32_t subr_number = argument_stack->top();
     251           0 :     argument_stack->pop();
     252           0 :     if (subr_number == dummy_result) {
     253             :       // For safety, we allow subr calls only with immediate subr numbers for
     254             :       // now. For example, we allow "123 callgsubr", but does not allow "100 12
     255             :       // add callgsubr". Please note that arithmetic and conditional operators
     256             :       // always push the |dummy_result| in this implementation.
     257           0 :       return OTS_FAILURE();
     258             :     }
     259             : 
     260             :     // See Adobe Technical Note #5176 (CFF), "16. Local/GlobalSubrs INDEXes."
     261           0 :     int32_t bias = 32768;
     262           0 :     if (subrs_index.count < 1240) {
     263           0 :       bias = 107;
     264           0 :     } else if (subrs_index.count < 33900) {
     265           0 :       bias = 1131;
     266             :     }
     267           0 :     subr_number += bias;
     268             : 
     269             :     // Sanity checks of |subr_number|.
     270           0 :     if (subr_number < 0) {
     271           0 :       return OTS_FAILURE();
     272             :     }
     273           0 :     if (subr_number >= kMaxSubrsCount) {
     274           0 :       return OTS_FAILURE();
     275             :     }
     276           0 :     if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number + 1)) {
     277           0 :       return OTS_FAILURE();  // The number is out-of-bounds.
     278             :     }
     279             : 
     280             :     // Prepare ots::Buffer where we're going to jump.
     281             :     const size_t length =
     282           0 :       subrs_index.offsets[subr_number + 1] - subrs_index.offsets[subr_number];
     283           0 :     if (length > kMaxCharStringLength) {
     284           0 :       return OTS_FAILURE();
     285             :     }
     286           0 :     const size_t offset = subrs_index.offsets[subr_number];
     287           0 :     cff_table->set_offset(offset);
     288           0 :     if (!cff_table->Skip(length)) {
     289           0 :       return OTS_FAILURE();
     290             :     }
     291           0 :     ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length);
     292             : 
     293           0 :     return ExecuteType2CharString(font,
     294             :                                   call_depth + 1,
     295             :                                   global_subrs_index,
     296             :                                   local_subrs_index,
     297             :                                   cff_table,
     298             :                                   &char_string_to_jump,
     299             :                                   argument_stack,
     300             :                                   out_found_endchar,
     301             :                                   in_out_found_width,
     302           0 :                                   in_out_num_stems);
     303             :   }
     304             : 
     305             :   case ots::kReturn:
     306           0 :     return true;
     307             : 
     308             :   case ots::kEndChar:
     309           0 :     *out_found_endchar = true;
     310           0 :     *in_out_found_width = true;  // just in case.
     311           0 :     return true;
     312             : 
     313             :   case ots::kHStem:
     314             :   case ots::kVStem:
     315             :   case ots::kHStemHm:
     316             :   case ots::kVStemHm: {
     317           0 :     bool successful = false;
     318           0 :     if (stack_size < 2) {
     319           0 :       return OTS_FAILURE();
     320             :     }
     321           0 :     if ((stack_size % 2) == 0) {
     322           0 :       successful = true;
     323           0 :     } else if ((!(*in_out_found_width)) && (((stack_size - 1) % 2) == 0)) {
     324             :       // The -1 is for "width" argument. For details, see Adobe Technical Note
     325             :       // #5177, page 16, note 4.
     326           0 :       successful = true;
     327             :     }
     328           0 :     (*in_out_num_stems) += (stack_size / 2);
     329           0 :     if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
     330           0 :       return OTS_FAILURE();
     331             :     }
     332           0 :     while (!argument_stack->empty())
     333           0 :       argument_stack->pop();
     334           0 :     *in_out_found_width = true;  // always set true since "w" might be 0 byte.
     335           0 :     return successful ? true : OTS_FAILURE();
     336             :   }
     337             : 
     338             :   case ots::kRMoveTo: {
     339           0 :     bool successful = false;
     340           0 :     if (stack_size == 2) {
     341           0 :       successful = true;
     342           0 :     } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) {
     343           0 :       successful = true;
     344             :     }
     345           0 :     while (!argument_stack->empty())
     346           0 :       argument_stack->pop();
     347           0 :     *in_out_found_width = true;
     348           0 :     return successful ? true : OTS_FAILURE();
     349             :   }
     350             : 
     351             :   case ots::kVMoveTo:
     352             :   case ots::kHMoveTo: {
     353           0 :     bool successful = false;
     354           0 :     if (stack_size == 1) {
     355           0 :       successful = true;
     356           0 :     } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) {
     357           0 :       successful = true;
     358             :     }
     359           0 :     while (!argument_stack->empty())
     360           0 :       argument_stack->pop();
     361           0 :     *in_out_found_width = true;
     362           0 :     return successful ? true : OTS_FAILURE();
     363             :   }
     364             : 
     365             :   case ots::kHintMask:
     366             :   case ots::kCntrMask: {
     367           0 :     bool successful = false;
     368           0 :     if (stack_size == 0) {
     369           0 :       successful = true;
     370           0 :     } else if ((!(*in_out_found_width)) && (stack_size == 1)) {
     371             :       // A number for "width" is found.
     372           0 :       successful = true;
     373           0 :     } else if ((!(*in_out_found_width)) ||  // in this case, any sizes are ok.
     374           0 :                ((stack_size % 2) == 0)) {
     375             :       // The numbers are vstem definition.
     376             :       // See Adobe Technical Note #5177, page 24, hintmask.
     377           0 :       (*in_out_num_stems) += (stack_size / 2);
     378           0 :       if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
     379           0 :         return OTS_FAILURE();
     380             :       }
     381           0 :       successful = true;
     382             :     }
     383           0 :     if (!successful) {
     384           0 :        return OTS_FAILURE();
     385             :     }
     386             : 
     387           0 :     if ((*in_out_num_stems) == 0) {
     388           0 :       return OTS_FAILURE();
     389             :     }
     390           0 :     const size_t mask_bytes = (*in_out_num_stems + 7) / 8;
     391           0 :     if (!char_string->Skip(mask_bytes)) {
     392           0 :       return OTS_FAILURE();
     393             :     }
     394           0 :     while (!argument_stack->empty())
     395           0 :       argument_stack->pop();
     396           0 :     *in_out_found_width = true;
     397           0 :     return true;
     398             :   }
     399             : 
     400             :   case ots::kRLineTo:
     401           0 :     if (!(*in_out_found_width)) {
     402             :       // The first stack-clearing operator should be one of hstem, hstemhm,
     403             :       // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or
     404             :       // endchar. For details, see Adobe Technical Note #5177, page 16, note 4.
     405           0 :       return OTS_FAILURE();
     406             :     }
     407           0 :     if (stack_size < 2) {
     408           0 :       return OTS_FAILURE();
     409             :     }
     410           0 :     if ((stack_size % 2) != 0) {
     411           0 :       return OTS_FAILURE();
     412             :     }
     413           0 :     while (!argument_stack->empty())
     414           0 :       argument_stack->pop();
     415           0 :     return true;
     416             : 
     417             :   case ots::kHLineTo:
     418             :   case ots::kVLineTo:
     419           0 :     if (!(*in_out_found_width)) {
     420           0 :       return OTS_FAILURE();
     421             :     }
     422           0 :     if (stack_size < 1) {
     423           0 :       return OTS_FAILURE();
     424             :     }
     425           0 :     while (!argument_stack->empty())
     426           0 :       argument_stack->pop();
     427           0 :     return true;
     428             : 
     429             :   case ots::kRRCurveTo:
     430           0 :     if (!(*in_out_found_width)) {
     431           0 :       return OTS_FAILURE();
     432             :     }
     433           0 :     if (stack_size < 6) {
     434           0 :       return OTS_FAILURE();
     435             :     }
     436           0 :     if ((stack_size % 6) != 0) {
     437           0 :       return OTS_FAILURE();
     438             :     }
     439           0 :     while (!argument_stack->empty())
     440           0 :       argument_stack->pop();
     441           0 :     return true;
     442             : 
     443             :   case ots::kRCurveLine:
     444           0 :     if (!(*in_out_found_width)) {
     445           0 :       return OTS_FAILURE();
     446             :     }
     447           0 :     if (stack_size < 8) {
     448           0 :       return OTS_FAILURE();
     449             :     }
     450           0 :     if (((stack_size - 2) % 6) != 0) {
     451           0 :       return OTS_FAILURE();
     452             :     }
     453           0 :     while (!argument_stack->empty())
     454           0 :       argument_stack->pop();
     455           0 :     return true;
     456             : 
     457             :   case ots::kRLineCurve:
     458           0 :     if (!(*in_out_found_width)) {
     459           0 :       return OTS_FAILURE();
     460             :     }
     461           0 :     if (stack_size < 8) {
     462           0 :       return OTS_FAILURE();
     463             :     }
     464           0 :     if (((stack_size - 6) % 2) != 0) {
     465           0 :       return OTS_FAILURE();
     466             :     }
     467           0 :     while (!argument_stack->empty())
     468           0 :       argument_stack->pop();
     469           0 :     return true;
     470             : 
     471             :   case ots::kVVCurveTo:
     472           0 :     if (!(*in_out_found_width)) {
     473           0 :       return OTS_FAILURE();
     474             :     }
     475           0 :     if (stack_size < 4) {
     476           0 :       return OTS_FAILURE();
     477             :     }
     478           0 :     if (((stack_size % 4) != 0) &&
     479           0 :         (((stack_size - 1) % 4) != 0)) {
     480           0 :       return OTS_FAILURE();
     481             :     }
     482           0 :     while (!argument_stack->empty())
     483           0 :       argument_stack->pop();
     484           0 :     return true;
     485             : 
     486             :   case ots::kHHCurveTo: {
     487           0 :     bool successful = false;
     488           0 :     if (!(*in_out_found_width)) {
     489           0 :       return OTS_FAILURE();
     490             :     }
     491           0 :     if (stack_size < 4) {
     492           0 :       return OTS_FAILURE();
     493             :     }
     494           0 :     if ((stack_size % 4) == 0) {
     495             :       // {dxa dxb dyb dxc}+
     496           0 :       successful = true;
     497           0 :     } else if (((stack_size - 1) % 4) == 0) {
     498             :       // dy1? {dxa dxb dyb dxc}+
     499           0 :       successful = true;
     500             :     }
     501           0 :     while (!argument_stack->empty())
     502           0 :       argument_stack->pop();
     503           0 :     return successful ? true : OTS_FAILURE();
     504             :   }
     505             : 
     506             :   case ots::kVHCurveTo:
     507             :   case ots::kHVCurveTo: {
     508           0 :     bool successful = false;
     509           0 :     if (!(*in_out_found_width)) {
     510           0 :       return OTS_FAILURE();
     511             :     }
     512           0 :     if (stack_size < 4) {
     513           0 :       return OTS_FAILURE();
     514             :     }
     515           0 :     if (((stack_size - 4) % 8) == 0) {
     516             :       // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}*
     517           0 :       successful = true;
     518           0 :     } else if ((stack_size >= 5) &&
     519           0 :                ((stack_size - 5) % 8) == 0) {
     520             :       // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf
     521           0 :       successful = true;
     522           0 :     } else if ((stack_size >= 8) &&
     523           0 :                ((stack_size - 8) % 8) == 0) {
     524             :       // {dxa dxb dyb dyc dyd dxe dye dxf}+
     525           0 :       successful = true;
     526           0 :     } else if ((stack_size >= 9) &&
     527           0 :                ((stack_size - 9) % 8) == 0) {
     528             :       // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
     529           0 :       successful = true;
     530             :     }
     531           0 :     while (!argument_stack->empty())
     532           0 :       argument_stack->pop();
     533           0 :     return successful ? true : OTS_FAILURE();
     534             :   }
     535             : 
     536             :   case ots::kDotSection:
     537             :     // Deprecated operator but harmless, we probably should drop it some how.
     538           0 :     if (stack_size != 0) {
     539           0 :       return OTS_FAILURE();
     540             :     }
     541           0 :     return true;
     542             : 
     543             :   case ots::kAnd:
     544             :   case ots::kOr:
     545             :   case ots::kEq:
     546             :   case ots::kAdd:
     547             :   case ots::kSub:
     548           0 :     if (stack_size < 2) {
     549           0 :       return OTS_FAILURE();
     550             :     }
     551           0 :     argument_stack->pop();
     552           0 :     argument_stack->pop();
     553           0 :     argument_stack->push(dummy_result);
     554             :     // TODO(yusukes): Implement this. We should push a real value for all
     555             :     // arithmetic and conditional operations.
     556           0 :     return true;
     557             : 
     558             :   case ots::kNot:
     559             :   case ots::kAbs:
     560             :   case ots::kNeg:
     561           0 :     if (stack_size < 1) {
     562           0 :       return OTS_FAILURE();
     563             :     }
     564           0 :     argument_stack->pop();
     565           0 :     argument_stack->push(dummy_result);
     566             :     // TODO(yusukes): Implement this. We should push a real value for all
     567             :     // arithmetic and conditional operations.
     568           0 :     return true;
     569             : 
     570             :   case ots::kDiv:
     571             :     // TODO(yusukes): Should detect div-by-zero errors.
     572           0 :     if (stack_size < 2) {
     573           0 :       return OTS_FAILURE();
     574             :     }
     575           0 :     argument_stack->pop();
     576           0 :     argument_stack->pop();
     577           0 :     argument_stack->push(dummy_result);
     578             :     // TODO(yusukes): Implement this. We should push a real value for all
     579             :     // arithmetic and conditional operations.
     580           0 :     return true;
     581             : 
     582             :   case ots::kDrop:
     583           0 :     if (stack_size < 1) {
     584           0 :       return OTS_FAILURE();
     585             :     }
     586           0 :     argument_stack->pop();
     587           0 :     return true;
     588             : 
     589             :   case ots::kPut:
     590             :   case ots::kGet:
     591             :   case ots::kIndex:
     592             :     // For now, just call OTS_FAILURE since there is no way to check whether the
     593             :     // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType
     594             :     // fonts I have (except malicious ones!) use the operators.
     595             :     // TODO(yusukes): Implement them in a secure way.
     596           0 :     return OTS_FAILURE();
     597             : 
     598             :   case ots::kRoll:
     599             :     // Likewise, just call OTS_FAILURE for kRoll since there is no way to check
     600             :     // whether |N| is smaller than the current stack depth or not.
     601             :     // TODO(yusukes): Implement them in a secure way.
     602           0 :     return OTS_FAILURE();
     603             : 
     604             :   case ots::kRandom:
     605             :     // For now, we don't handle the 'random' operator since the operator makes
     606             :     // it hard to analyze hinting code statically.
     607           0 :     return OTS_FAILURE();
     608             : 
     609             :   case ots::kIfElse:
     610           0 :     if (stack_size < 4) {
     611           0 :       return OTS_FAILURE();
     612             :     }
     613           0 :     argument_stack->pop();
     614           0 :     argument_stack->pop();
     615           0 :     argument_stack->pop();
     616           0 :     argument_stack->pop();
     617           0 :     argument_stack->push(dummy_result);
     618             :     // TODO(yusukes): Implement this. We should push a real value for all
     619             :     // arithmetic and conditional operations.
     620           0 :     return true;
     621             : 
     622             :   case ots::kMul:
     623             :     // TODO(yusukes): Should detect overflows.
     624           0 :     if (stack_size < 2) {
     625           0 :       return OTS_FAILURE();
     626             :     }
     627           0 :     argument_stack->pop();
     628           0 :     argument_stack->pop();
     629           0 :     argument_stack->push(dummy_result);
     630             :     // TODO(yusukes): Implement this. We should push a real value for all
     631             :     // arithmetic and conditional operations.
     632           0 :     return true;
     633             : 
     634             :   case ots::kSqrt:
     635             :     // TODO(yusukes): Should check if the argument is negative.
     636           0 :     if (stack_size < 1) {
     637           0 :       return OTS_FAILURE();
     638             :     }
     639           0 :     argument_stack->pop();
     640           0 :     argument_stack->push(dummy_result);
     641             :     // TODO(yusukes): Implement this. We should push a real value for all
     642             :     // arithmetic and conditional operations.
     643           0 :     return true;
     644             : 
     645             :   case ots::kDup:
     646           0 :     if (stack_size < 1) {
     647           0 :       return OTS_FAILURE();
     648             :     }
     649           0 :     argument_stack->pop();
     650           0 :     argument_stack->push(dummy_result);
     651           0 :     argument_stack->push(dummy_result);
     652           0 :     if (argument_stack->size() > kMaxArgumentStack) {
     653           0 :       return OTS_FAILURE();
     654             :     }
     655             :     // TODO(yusukes): Implement this. We should push a real value for all
     656             :     // arithmetic and conditional operations.
     657           0 :     return true;
     658             : 
     659             :   case ots::kExch:
     660           0 :     if (stack_size < 2) {
     661           0 :       return OTS_FAILURE();
     662             :     }
     663           0 :     argument_stack->pop();
     664           0 :     argument_stack->pop();
     665           0 :     argument_stack->push(dummy_result);
     666           0 :     argument_stack->push(dummy_result);
     667             :     // TODO(yusukes): Implement this. We should push a real value for all
     668             :     // arithmetic and conditional operations.
     669           0 :     return true;
     670             : 
     671             :   case ots::kHFlex:
     672           0 :     if (!(*in_out_found_width)) {
     673           0 :       return OTS_FAILURE();
     674             :     }
     675           0 :     if (stack_size != 7) {
     676           0 :       return OTS_FAILURE();
     677             :     }
     678           0 :     while (!argument_stack->empty())
     679           0 :       argument_stack->pop();
     680           0 :     return true;
     681             : 
     682             :   case ots::kFlex:
     683           0 :     if (!(*in_out_found_width)) {
     684           0 :       return OTS_FAILURE();
     685             :     }
     686           0 :     if (stack_size != 13) {
     687           0 :       return OTS_FAILURE();
     688             :     }
     689           0 :     while (!argument_stack->empty())
     690           0 :       argument_stack->pop();
     691           0 :     return true;
     692             : 
     693             :   case ots::kHFlex1:
     694           0 :     if (!(*in_out_found_width)) {
     695           0 :       return OTS_FAILURE();
     696             :     }
     697           0 :     if (stack_size != 9) {
     698           0 :       return OTS_FAILURE();
     699             :     }
     700           0 :     while (!argument_stack->empty())
     701           0 :       argument_stack->pop();
     702           0 :     return true;
     703             : 
     704             :   case ots::kFlex1:
     705           0 :     if (!(*in_out_found_width)) {
     706           0 :       return OTS_FAILURE();
     707             :     }
     708           0 :     if (stack_size != 11) {
     709           0 :       return OTS_FAILURE();
     710             :     }
     711           0 :     while (!argument_stack->empty())
     712           0 :       argument_stack->pop();
     713           0 :     return true;
     714             :   }
     715             : 
     716           0 :   return OTS_FAILURE_MSG("Undefined operator: %d (0x%x)", op, op);
     717             : }
     718             : 
     719             : // Executes |char_string| and updates |argument_stack|.
     720             : //
     721             : // call_depth: The current call depth. Initial value is zero.
     722             : // global_subrs_index: Global subroutines.
     723             : // local_subrs_index: Local subroutines for the current glyph.
     724             : // cff_table: A whole CFF table which contains all global and local subroutines.
     725             : // char_string: A charstring we'll execute. |char_string| can be a main routine
     726             : //              in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr.
     727             : // argument_stack: The stack which an operator in |char_string| operates.
     728             : // out_found_endchar: true is set if |char_string| contains 'endchar'.
     729             : // in_out_found_width: true is set if |char_string| contains 'width' byte (which
     730             : //                     is 0 or 1 byte.)
     731             : // in_out_num_stems: total number of hstems and vstems processed so far.
     732           0 : bool ExecuteType2CharString(ots::Font *font,
     733             :                             size_t call_depth,
     734             :                             const ots::CFFIndex& global_subrs_index,
     735             :                             const ots::CFFIndex& local_subrs_index,
     736             :                             ots::Buffer *cff_table,
     737             :                             ots::Buffer *char_string,
     738             :                             std::stack<int32_t> *argument_stack,
     739             :                             bool *out_found_endchar,
     740             :                             bool *in_out_found_width,
     741             :                             size_t *in_out_num_stems) {
     742           0 :   if (call_depth > kMaxSubrNesting) {
     743           0 :     return OTS_FAILURE();
     744             :   }
     745           0 :   *out_found_endchar = false;
     746             : 
     747           0 :   const size_t length = char_string->length();
     748           0 :   while (char_string->offset() < length) {
     749           0 :     int32_t operator_or_operand = 0;
     750           0 :     bool is_operator = false;
     751           0 :     if (!ReadNextNumberFromType2CharString(char_string,
     752             :                                            &operator_or_operand,
     753             :                                            &is_operator)) {
     754           0 :       return OTS_FAILURE();
     755             :     }
     756             : 
     757             : #ifdef DUMP_T2CHARSTRING
     758             :     /*
     759             :       You can dump all operators and operands (except mask bytes for hintmask
     760             :       and cntrmask) by the following code:
     761             :     */
     762             : 
     763             :       if (!is_operator) {
     764             :         std::fprintf(stderr, "#%d# ", operator_or_operand);
     765             :       } else {
     766             :         std::fprintf(stderr, "#%s#\n",
     767             :            Type2CharStringOperatorToString(
     768             :                ots::Type2CharStringOperator(operator_or_operand))
     769             :            );
     770             :       }
     771             : #endif
     772             : 
     773           0 :     if (!is_operator) {
     774           0 :       argument_stack->push(operator_or_operand);
     775           0 :       if (argument_stack->size() > kMaxArgumentStack) {
     776           0 :         return OTS_FAILURE();
     777             :       }
     778           0 :       continue;
     779             :     }
     780             : 
     781             :     // An operator is found. Execute it.
     782           0 :     if (!ExecuteType2CharStringOperator(font,
     783             :                                         operator_or_operand,
     784             :                                         call_depth,
     785             :                                         global_subrs_index,
     786             :                                         local_subrs_index,
     787             :                                         cff_table,
     788             :                                         char_string,
     789             :                                         argument_stack,
     790             :                                         out_found_endchar,
     791             :                                         in_out_found_width,
     792             :                                         in_out_num_stems)) {
     793           0 :       return OTS_FAILURE();
     794             :     }
     795           0 :     if (*out_found_endchar) {
     796           0 :       return true;
     797             :     }
     798           0 :     if (operator_or_operand == ots::kReturn) {
     799           0 :       return true;
     800             :     }
     801             :   }
     802             : 
     803             :   // No endchar operator is found.
     804           0 :   return OTS_FAILURE();
     805             : }
     806             : 
     807             : // Selects a set of subroutings for |glyph_index| from |cff| and sets it on
     808             : // |out_local_subrs_to_use|. Returns true on success.
     809           0 : bool SelectLocalSubr(const std::map<uint16_t, uint8_t> &fd_select,
     810             :                      const std::vector<ots::CFFIndex *> &local_subrs_per_font,
     811             :                      const ots::CFFIndex *local_subrs,
     812             :                      uint16_t glyph_index,  // 0-origin
     813             :                      const ots::CFFIndex **out_local_subrs_to_use) {
     814           0 :   *out_local_subrs_to_use = NULL;
     815             : 
     816             :   // First, find local subrs from |local_subrs_per_font|.
     817           0 :   if ((fd_select.size() > 0) &&
     818           0 :       (!local_subrs_per_font.empty())) {
     819             :     // Look up FDArray index for the glyph.
     820             :     std::map<uint16_t, uint8_t>::const_iterator iter =
     821           0 :         fd_select.find(glyph_index);
     822           0 :     if (iter == fd_select.end()) {
     823           0 :       return OTS_FAILURE();
     824             :     }
     825           0 :     const uint8_t fd_index = iter->second;
     826           0 :     if (fd_index >= local_subrs_per_font.size()) {
     827           0 :       return OTS_FAILURE();
     828             :     }
     829           0 :     *out_local_subrs_to_use = local_subrs_per_font.at(fd_index);
     830           0 :   } else if (local_subrs) {
     831             :     // Second, try to use |local_subrs|. Most Latin fonts don't have FDSelect
     832             :     // entries. If The font has a local subrs index associated with the Top
     833             :     // DICT (not FDArrays), use it.
     834           0 :     *out_local_subrs_to_use = local_subrs;
     835             :   } else {
     836             :     // Just return NULL.
     837           0 :     *out_local_subrs_to_use = NULL;
     838             :   }
     839             : 
     840           0 :   return true;
     841             : }
     842             : 
     843             : }  // namespace
     844             : 
     845             : namespace ots {
     846             : 
     847           0 : bool ValidateType2CharStringIndex(
     848             :     ots::Font *font,
     849             :     const CFFIndex& char_strings_index,
     850             :     const CFFIndex& global_subrs_index,
     851             :     const std::map<uint16_t, uint8_t> &fd_select,
     852             :     const std::vector<CFFIndex *> &local_subrs_per_font,
     853             :     const CFFIndex *local_subrs,
     854             :     Buffer* cff_table) {
     855           0 :   if (char_strings_index.offsets.size() == 0) {
     856           0 :     return OTS_FAILURE();  // no charstring.
     857             :   }
     858             : 
     859             :   // For each glyph, validate the corresponding charstring.
     860           0 :   for (unsigned i = 1; i < char_strings_index.offsets.size(); ++i) {
     861             :     // Prepare a Buffer object, |char_string|, which contains the charstring
     862             :     // for the |i|-th glyph.
     863             :     const size_t length =
     864           0 :       char_strings_index.offsets[i] - char_strings_index.offsets[i - 1];
     865           0 :     if (length > kMaxCharStringLength) {
     866           0 :       return OTS_FAILURE();
     867             :     }
     868           0 :     const size_t offset = char_strings_index.offsets[i - 1];
     869           0 :     cff_table->set_offset(offset);
     870           0 :     if (!cff_table->Skip(length)) {
     871           0 :       return OTS_FAILURE();
     872             :     }
     873           0 :     Buffer char_string(cff_table->buffer() + offset, length);
     874             : 
     875             :     // Get a local subrs for the glyph.
     876           0 :     const unsigned glyph_index = i - 1;  // index in the map is 0-origin.
     877           0 :     const CFFIndex *local_subrs_to_use = NULL;
     878           0 :     if (!SelectLocalSubr(fd_select,
     879             :                          local_subrs_per_font,
     880             :                          local_subrs,
     881             :                          glyph_index,
     882             :                          &local_subrs_to_use)) {
     883           0 :       return OTS_FAILURE();
     884             :     }
     885             :     // If |local_subrs_to_use| is still NULL, use an empty one.
     886           0 :     CFFIndex default_empty_subrs;
     887           0 :     if (!local_subrs_to_use){
     888           0 :       local_subrs_to_use = &default_empty_subrs;
     889             :     }
     890             : 
     891             :     // Check a charstring for the |i|-th glyph.
     892           0 :     std::stack<int32_t> argument_stack;
     893           0 :     bool found_endchar = false;
     894           0 :     bool found_width = false;
     895           0 :     size_t num_stems = 0;
     896           0 :     if (!ExecuteType2CharString(font,
     897             :                                 0 /* initial call_depth is zero */,
     898             :                                 global_subrs_index, *local_subrs_to_use,
     899             :                                 cff_table, &char_string, &argument_stack,
     900             :                                 &found_endchar, &found_width, &num_stems)) {
     901           0 :       return OTS_FAILURE();
     902             :     }
     903           0 :     if (!found_endchar) {
     904           0 :       return OTS_FAILURE();
     905             :     }
     906             :   }
     907           0 :   return true;
     908             : }
     909             : 
     910             : }  // namespace ots
     911             : 
     912             : #undef TABLE_NAME

Generated by: LCOV version 1.13