LCOV - code coverage report
Current view: directory - gfx/ots/src - cff_type2_charstring.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 421 0 0.0 %
Date: 2012-06-02 Functions: 6 0 0.0 %

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

Generated by: LCOV version 1.7