OLD | NEW |
(Empty) | |
| 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::OpenTypeFile *file, |
| 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 bool ReadNextNumberFromType2CharString(ots::Buffer *char_string, |
| 154 int32_t *out_number, |
| 155 bool *out_is_operator) { |
| 156 uint8_t v = 0; |
| 157 if (!char_string->ReadU8(&v)) { |
| 158 return OTS_FAILURE(); |
| 159 } |
| 160 *out_is_operator = false; |
| 161 |
| 162 // The conversion algorithm is described in Adobe Technical Note #5177, page |
| 163 // 13, Table 1. |
| 164 if (v <= 11) { |
| 165 *out_number = v; |
| 166 *out_is_operator = true; |
| 167 } else if (v == 12) { |
| 168 uint16_t result = (v << 8); |
| 169 if (!char_string->ReadU8(&v)) { |
| 170 return OTS_FAILURE(); |
| 171 } |
| 172 result += v; |
| 173 *out_number = result; |
| 174 *out_is_operator = true; |
| 175 } else if (v <= 27) { |
| 176 // Special handling for v==19 and v==20 are implemented in |
| 177 // ExecuteType2CharStringOperator(). |
| 178 *out_number = v; |
| 179 *out_is_operator = true; |
| 180 } else if (v == 28) { |
| 181 if (!char_string->ReadU8(&v)) { |
| 182 return OTS_FAILURE(); |
| 183 } |
| 184 uint16_t result = (v << 8); |
| 185 if (!char_string->ReadU8(&v)) { |
| 186 return OTS_FAILURE(); |
| 187 } |
| 188 result += v; |
| 189 *out_number = result; |
| 190 } else if (v <= 31) { |
| 191 *out_number = v; |
| 192 *out_is_operator = true; |
| 193 } else if (v <= 246) { |
| 194 *out_number = static_cast<int32_t>(v) - 139; |
| 195 } else if (v <= 250) { |
| 196 uint8_t w = 0; |
| 197 if (!char_string->ReadU8(&w)) { |
| 198 return OTS_FAILURE(); |
| 199 } |
| 200 *out_number = ((static_cast<int32_t>(v) - 247) * 256) + |
| 201 static_cast<int32_t>(w) + 108; |
| 202 } else if (v <= 254) { |
| 203 uint8_t w = 0; |
| 204 if (!char_string->ReadU8(&w)) { |
| 205 return OTS_FAILURE(); |
| 206 } |
| 207 *out_number = -((static_cast<int32_t>(v) - 251) * 256) - |
| 208 static_cast<int32_t>(w) - 108; |
| 209 } 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 if (!char_string->Skip(4)) { |
| 214 return OTS_FAILURE(); |
| 215 } |
| 216 *out_number = dummy_result; |
| 217 } else { |
| 218 return OTS_FAILURE(); |
| 219 } |
| 220 |
| 221 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 bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file, |
| 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 const size_t stack_size = argument_stack->size(); |
| 240 |
| 241 switch (op) { |
| 242 case ots::kCallSubr: |
| 243 case ots::kCallGSubr: { |
| 244 const ots::CFFIndex& subrs_index = |
| 245 (op == ots::kCallSubr ? local_subrs_index : global_subrs_index); |
| 246 |
| 247 if (stack_size < 1) { |
| 248 return OTS_FAILURE(); |
| 249 } |
| 250 int32_t subr_number = argument_stack->top(); |
| 251 argument_stack->pop(); |
| 252 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 return OTS_FAILURE(); |
| 258 } |
| 259 |
| 260 // See Adobe Technical Note #5176 (CFF), "16. Local/GlobalSubrs INDEXes." |
| 261 int32_t bias = 32768; |
| 262 if (subrs_index.count < 1240) { |
| 263 bias = 107; |
| 264 } else if (subrs_index.count < 33900) { |
| 265 bias = 1131; |
| 266 } |
| 267 subr_number += bias; |
| 268 |
| 269 // Sanity checks of |subr_number|. |
| 270 if (subr_number < 0) { |
| 271 return OTS_FAILURE(); |
| 272 } |
| 273 if (subr_number >= kMaxSubrsCount) { |
| 274 return OTS_FAILURE(); |
| 275 } |
| 276 if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number + 1)) { |
| 277 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 subrs_index.offsets[subr_number + 1] - subrs_index.offsets[subr_number]; |
| 283 if (length > kMaxCharStringLength) { |
| 284 return OTS_FAILURE(); |
| 285 } |
| 286 const size_t offset = subrs_index.offsets[subr_number]; |
| 287 cff_table->set_offset(offset); |
| 288 if (!cff_table->Skip(length)) { |
| 289 return OTS_FAILURE(); |
| 290 } |
| 291 ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length); |
| 292 |
| 293 return ExecuteType2CharString(file, |
| 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 in_out_num_stems); |
| 303 } |
| 304 |
| 305 case ots::kReturn: |
| 306 return true; |
| 307 |
| 308 case ots::kEndChar: |
| 309 *out_found_endchar = true; |
| 310 *in_out_found_width = true; // just in case. |
| 311 return true; |
| 312 |
| 313 case ots::kHStem: |
| 314 case ots::kVStem: |
| 315 case ots::kHStemHm: |
| 316 case ots::kVStemHm: { |
| 317 bool successful = false; |
| 318 if (stack_size < 2) { |
| 319 return OTS_FAILURE(); |
| 320 } |
| 321 if ((stack_size % 2) == 0) { |
| 322 successful = true; |
| 323 } 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 successful = true; |
| 327 } |
| 328 (*in_out_num_stems) += (stack_size / 2); |
| 329 if ((*in_out_num_stems) > kMaxNumberOfStemHints) { |
| 330 return OTS_FAILURE(); |
| 331 } |
| 332 while (!argument_stack->empty()) |
| 333 argument_stack->pop(); |
| 334 *in_out_found_width = true; // always set true since "w" might be 0 byte. |
| 335 return successful ? true : OTS_FAILURE(); |
| 336 } |
| 337 |
| 338 case ots::kRMoveTo: { |
| 339 bool successful = false; |
| 340 if (stack_size == 2) { |
| 341 successful = true; |
| 342 } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) { |
| 343 successful = true; |
| 344 } |
| 345 while (!argument_stack->empty()) |
| 346 argument_stack->pop(); |
| 347 *in_out_found_width = true; |
| 348 return successful ? true : OTS_FAILURE(); |
| 349 } |
| 350 |
| 351 case ots::kVMoveTo: |
| 352 case ots::kHMoveTo: { |
| 353 bool successful = false; |
| 354 if (stack_size == 1) { |
| 355 successful = true; |
| 356 } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) { |
| 357 successful = true; |
| 358 } |
| 359 while (!argument_stack->empty()) |
| 360 argument_stack->pop(); |
| 361 *in_out_found_width = true; |
| 362 return successful ? true : OTS_FAILURE(); |
| 363 } |
| 364 |
| 365 case ots::kHintMask: |
| 366 case ots::kCntrMask: { |
| 367 bool successful = false; |
| 368 if (stack_size == 0) { |
| 369 successful = true; |
| 370 } else if ((!(*in_out_found_width)) && (stack_size == 1)) { |
| 371 // A number for "width" is found. |
| 372 successful = true; |
| 373 } else if ((!(*in_out_found_width)) || // in this case, any sizes are ok. |
| 374 ((stack_size % 2) == 0)) { |
| 375 // The numbers are vstem definition. |
| 376 // See Adobe Technical Note #5177, page 24, hintmask. |
| 377 (*in_out_num_stems) += (stack_size / 2); |
| 378 if ((*in_out_num_stems) > kMaxNumberOfStemHints) { |
| 379 return OTS_FAILURE(); |
| 380 } |
| 381 successful = true; |
| 382 } |
| 383 if (!successful) { |
| 384 return OTS_FAILURE(); |
| 385 } |
| 386 |
| 387 if ((*in_out_num_stems) == 0) { |
| 388 return OTS_FAILURE(); |
| 389 } |
| 390 const size_t mask_bytes = (*in_out_num_stems + 7) / 8; |
| 391 if (!char_string->Skip(mask_bytes)) { |
| 392 return OTS_FAILURE(); |
| 393 } |
| 394 while (!argument_stack->empty()) |
| 395 argument_stack->pop(); |
| 396 *in_out_found_width = true; |
| 397 return true; |
| 398 } |
| 399 |
| 400 case ots::kRLineTo: |
| 401 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 return OTS_FAILURE(); |
| 406 } |
| 407 if (stack_size < 2) { |
| 408 return OTS_FAILURE(); |
| 409 } |
| 410 if ((stack_size % 2) != 0) { |
| 411 return OTS_FAILURE(); |
| 412 } |
| 413 while (!argument_stack->empty()) |
| 414 argument_stack->pop(); |
| 415 return true; |
| 416 |
| 417 case ots::kHLineTo: |
| 418 case ots::kVLineTo: |
| 419 if (!(*in_out_found_width)) { |
| 420 return OTS_FAILURE(); |
| 421 } |
| 422 if (stack_size < 1) { |
| 423 return OTS_FAILURE(); |
| 424 } |
| 425 while (!argument_stack->empty()) |
| 426 argument_stack->pop(); |
| 427 return true; |
| 428 |
| 429 case ots::kRRCurveTo: |
| 430 if (!(*in_out_found_width)) { |
| 431 return OTS_FAILURE(); |
| 432 } |
| 433 if (stack_size < 6) { |
| 434 return OTS_FAILURE(); |
| 435 } |
| 436 if ((stack_size % 6) != 0) { |
| 437 return OTS_FAILURE(); |
| 438 } |
| 439 while (!argument_stack->empty()) |
| 440 argument_stack->pop(); |
| 441 return true; |
| 442 |
| 443 case ots::kRCurveLine: |
| 444 if (!(*in_out_found_width)) { |
| 445 return OTS_FAILURE(); |
| 446 } |
| 447 if (stack_size < 8) { |
| 448 return OTS_FAILURE(); |
| 449 } |
| 450 if (((stack_size - 2) % 6) != 0) { |
| 451 return OTS_FAILURE(); |
| 452 } |
| 453 while (!argument_stack->empty()) |
| 454 argument_stack->pop(); |
| 455 return true; |
| 456 |
| 457 case ots::kRLineCurve: |
| 458 if (!(*in_out_found_width)) { |
| 459 return OTS_FAILURE(); |
| 460 } |
| 461 if (stack_size < 8) { |
| 462 return OTS_FAILURE(); |
| 463 } |
| 464 if (((stack_size - 6) % 2) != 0) { |
| 465 return OTS_FAILURE(); |
| 466 } |
| 467 while (!argument_stack->empty()) |
| 468 argument_stack->pop(); |
| 469 return true; |
| 470 |
| 471 case ots::kVVCurveTo: |
| 472 if (!(*in_out_found_width)) { |
| 473 return OTS_FAILURE(); |
| 474 } |
| 475 if (stack_size < 4) { |
| 476 return OTS_FAILURE(); |
| 477 } |
| 478 if (((stack_size % 4) != 0) && |
| 479 (((stack_size - 1) % 4) != 0)) { |
| 480 return OTS_FAILURE(); |
| 481 } |
| 482 while (!argument_stack->empty()) |
| 483 argument_stack->pop(); |
| 484 return true; |
| 485 |
| 486 case ots::kHHCurveTo: { |
| 487 bool successful = false; |
| 488 if (!(*in_out_found_width)) { |
| 489 return OTS_FAILURE(); |
| 490 } |
| 491 if (stack_size < 4) { |
| 492 return OTS_FAILURE(); |
| 493 } |
| 494 if ((stack_size % 4) == 0) { |
| 495 // {dxa dxb dyb dxc}+ |
| 496 successful = true; |
| 497 } else if (((stack_size - 1) % 4) == 0) { |
| 498 // dy1? {dxa dxb dyb dxc}+ |
| 499 successful = true; |
| 500 } |
| 501 while (!argument_stack->empty()) |
| 502 argument_stack->pop(); |
| 503 return successful ? true : OTS_FAILURE(); |
| 504 } |
| 505 |
| 506 case ots::kVHCurveTo: |
| 507 case ots::kHVCurveTo: { |
| 508 bool successful = false; |
| 509 if (!(*in_out_found_width)) { |
| 510 return OTS_FAILURE(); |
| 511 } |
| 512 if (stack_size < 4) { |
| 513 return OTS_FAILURE(); |
| 514 } |
| 515 if (((stack_size - 4) % 8) == 0) { |
| 516 // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* |
| 517 successful = true; |
| 518 } else if ((stack_size >= 5) && |
| 519 ((stack_size - 5) % 8) == 0) { |
| 520 // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf |
| 521 successful = true; |
| 522 } else if ((stack_size >= 8) && |
| 523 ((stack_size - 8) % 8) == 0) { |
| 524 // {dxa dxb dyb dyc dyd dxe dye dxf}+ |
| 525 successful = true; |
| 526 } else if ((stack_size >= 9) && |
| 527 ((stack_size - 9) % 8) == 0) { |
| 528 // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? |
| 529 successful = true; |
| 530 } |
| 531 while (!argument_stack->empty()) |
| 532 argument_stack->pop(); |
| 533 return successful ? true : OTS_FAILURE(); |
| 534 } |
| 535 |
| 536 case ots::kDotSection: |
| 537 // Deprecated operator but harmless, we probably should drop it some how. |
| 538 if (stack_size != 0) { |
| 539 return OTS_FAILURE(); |
| 540 } |
| 541 return true; |
| 542 |
| 543 case ots::kAnd: |
| 544 case ots::kOr: |
| 545 case ots::kEq: |
| 546 case ots::kAdd: |
| 547 case ots::kSub: |
| 548 if (stack_size < 2) { |
| 549 return OTS_FAILURE(); |
| 550 } |
| 551 argument_stack->pop(); |
| 552 argument_stack->pop(); |
| 553 argument_stack->push(dummy_result); |
| 554 // TODO(yusukes): Implement this. We should push a real value for all |
| 555 // arithmetic and conditional operations. |
| 556 return true; |
| 557 |
| 558 case ots::kNot: |
| 559 case ots::kAbs: |
| 560 case ots::kNeg: |
| 561 if (stack_size < 1) { |
| 562 return OTS_FAILURE(); |
| 563 } |
| 564 argument_stack->pop(); |
| 565 argument_stack->push(dummy_result); |
| 566 // TODO(yusukes): Implement this. We should push a real value for all |
| 567 // arithmetic and conditional operations. |
| 568 return true; |
| 569 |
| 570 case ots::kDiv: |
| 571 // TODO(yusukes): Should detect div-by-zero errors. |
| 572 if (stack_size < 2) { |
| 573 return OTS_FAILURE(); |
| 574 } |
| 575 argument_stack->pop(); |
| 576 argument_stack->pop(); |
| 577 argument_stack->push(dummy_result); |
| 578 // TODO(yusukes): Implement this. We should push a real value for all |
| 579 // arithmetic and conditional operations. |
| 580 return true; |
| 581 |
| 582 case ots::kDrop: |
| 583 if (stack_size < 1) { |
| 584 return OTS_FAILURE(); |
| 585 } |
| 586 argument_stack->pop(); |
| 587 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 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 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 return OTS_FAILURE(); |
| 608 |
| 609 case ots::kIfElse: |
| 610 if (stack_size < 4) { |
| 611 return OTS_FAILURE(); |
| 612 } |
| 613 argument_stack->pop(); |
| 614 argument_stack->pop(); |
| 615 argument_stack->pop(); |
| 616 argument_stack->pop(); |
| 617 argument_stack->push(dummy_result); |
| 618 // TODO(yusukes): Implement this. We should push a real value for all |
| 619 // arithmetic and conditional operations. |
| 620 return true; |
| 621 |
| 622 case ots::kMul: |
| 623 // TODO(yusukes): Should detect overflows. |
| 624 if (stack_size < 2) { |
| 625 return OTS_FAILURE(); |
| 626 } |
| 627 argument_stack->pop(); |
| 628 argument_stack->pop(); |
| 629 argument_stack->push(dummy_result); |
| 630 // TODO(yusukes): Implement this. We should push a real value for all |
| 631 // arithmetic and conditional operations. |
| 632 return true; |
| 633 |
| 634 case ots::kSqrt: |
| 635 // TODO(yusukes): Should check if the argument is negative. |
| 636 if (stack_size < 1) { |
| 637 return OTS_FAILURE(); |
| 638 } |
| 639 argument_stack->pop(); |
| 640 argument_stack->push(dummy_result); |
| 641 // TODO(yusukes): Implement this. We should push a real value for all |
| 642 // arithmetic and conditional operations. |
| 643 return true; |
| 644 |
| 645 case ots::kDup: |
| 646 if (stack_size < 1) { |
| 647 return OTS_FAILURE(); |
| 648 } |
| 649 argument_stack->pop(); |
| 650 argument_stack->push(dummy_result); |
| 651 argument_stack->push(dummy_result); |
| 652 if (argument_stack->size() > kMaxArgumentStack) { |
| 653 return OTS_FAILURE(); |
| 654 } |
| 655 // TODO(yusukes): Implement this. We should push a real value for all |
| 656 // arithmetic and conditional operations. |
| 657 return true; |
| 658 |
| 659 case ots::kExch: |
| 660 if (stack_size < 2) { |
| 661 return OTS_FAILURE(); |
| 662 } |
| 663 argument_stack->pop(); |
| 664 argument_stack->pop(); |
| 665 argument_stack->push(dummy_result); |
| 666 argument_stack->push(dummy_result); |
| 667 // TODO(yusukes): Implement this. We should push a real value for all |
| 668 // arithmetic and conditional operations. |
| 669 return true; |
| 670 |
| 671 case ots::kHFlex: |
| 672 if (!(*in_out_found_width)) { |
| 673 return OTS_FAILURE(); |
| 674 } |
| 675 if (stack_size != 7) { |
| 676 return OTS_FAILURE(); |
| 677 } |
| 678 while (!argument_stack->empty()) |
| 679 argument_stack->pop(); |
| 680 return true; |
| 681 |
| 682 case ots::kFlex: |
| 683 if (!(*in_out_found_width)) { |
| 684 return OTS_FAILURE(); |
| 685 } |
| 686 if (stack_size != 13) { |
| 687 return OTS_FAILURE(); |
| 688 } |
| 689 while (!argument_stack->empty()) |
| 690 argument_stack->pop(); |
| 691 return true; |
| 692 |
| 693 case ots::kHFlex1: |
| 694 if (!(*in_out_found_width)) { |
| 695 return OTS_FAILURE(); |
| 696 } |
| 697 if (stack_size != 9) { |
| 698 return OTS_FAILURE(); |
| 699 } |
| 700 while (!argument_stack->empty()) |
| 701 argument_stack->pop(); |
| 702 return true; |
| 703 |
| 704 case ots::kFlex1: |
| 705 if (!(*in_out_found_width)) { |
| 706 return OTS_FAILURE(); |
| 707 } |
| 708 if (stack_size != 11) { |
| 709 return OTS_FAILURE(); |
| 710 } |
| 711 while (!argument_stack->empty()) |
| 712 argument_stack->pop(); |
| 713 return true; |
| 714 } |
| 715 |
| 716 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 bool ExecuteType2CharString(ots::OpenTypeFile *file, |
| 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 if (call_depth > kMaxSubrNesting) { |
| 743 return OTS_FAILURE(); |
| 744 } |
| 745 *out_found_endchar = false; |
| 746 |
| 747 const size_t length = char_string->length(); |
| 748 while (char_string->offset() < length) { |
| 749 int32_t operator_or_operand = 0; |
| 750 bool is_operator = false; |
| 751 if (!ReadNextNumberFromType2CharString(char_string, |
| 752 &operator_or_operand, |
| 753 &is_operator)) { |
| 754 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 if (!is_operator) { |
| 774 argument_stack->push(operator_or_operand); |
| 775 if (argument_stack->size() > kMaxArgumentStack) { |
| 776 return OTS_FAILURE(); |
| 777 } |
| 778 continue; |
| 779 } |
| 780 |
| 781 // An operator is found. Execute it. |
| 782 if (!ExecuteType2CharStringOperator(file, |
| 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 return OTS_FAILURE(); |
| 794 } |
| 795 if (*out_found_endchar) { |
| 796 return true; |
| 797 } |
| 798 if (operator_or_operand == ots::kReturn) { |
| 799 return true; |
| 800 } |
| 801 } |
| 802 |
| 803 // No endchar operator is found. |
| 804 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 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 *out_local_subrs_to_use = NULL; |
| 815 |
| 816 // First, find local subrs from |local_subrs_per_font|. |
| 817 if ((fd_select.size() > 0) && |
| 818 (!local_subrs_per_font.empty())) { |
| 819 // Look up FDArray index for the glyph. |
| 820 std::map<uint16_t, uint8_t>::const_iterator iter = |
| 821 fd_select.find(glyph_index); |
| 822 if (iter == fd_select.end()) { |
| 823 return OTS_FAILURE(); |
| 824 } |
| 825 const uint8_t fd_index = iter->second; |
| 826 if (fd_index >= local_subrs_per_font.size()) { |
| 827 return OTS_FAILURE(); |
| 828 } |
| 829 *out_local_subrs_to_use = local_subrs_per_font.at(fd_index); |
| 830 } 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 *out_local_subrs_to_use = local_subrs; |
| 835 } else { |
| 836 // Just return NULL. |
| 837 *out_local_subrs_to_use = NULL; |
| 838 } |
| 839 |
| 840 return true; |
| 841 } |
| 842 |
| 843 } // namespace |
| 844 |
| 845 namespace ots { |
| 846 |
| 847 bool ValidateType2CharStringIndex( |
| 848 ots::OpenTypeFile *file, |
| 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 const uint16_t num_offsets = |
| 856 static_cast<uint16_t>(char_strings_index.offsets.size()); |
| 857 if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) { |
| 858 return OTS_FAILURE(); // no charstring. |
| 859 } |
| 860 |
| 861 // For each glyph, validate the corresponding charstring. |
| 862 for (uint16_t i = 1; i < num_offsets; ++i) { |
| 863 // Prepare a Buffer object, |char_string|, which contains the charstring |
| 864 // for the |i|-th glyph. |
| 865 const size_t length = |
| 866 char_strings_index.offsets[i] - char_strings_index.offsets[i - 1]; |
| 867 if (length > kMaxCharStringLength) { |
| 868 return OTS_FAILURE(); |
| 869 } |
| 870 const size_t offset = char_strings_index.offsets[i - 1]; |
| 871 cff_table->set_offset(offset); |
| 872 if (!cff_table->Skip(length)) { |
| 873 return OTS_FAILURE(); |
| 874 } |
| 875 Buffer char_string(cff_table->buffer() + offset, length); |
| 876 |
| 877 // Get a local subrs for the glyph. |
| 878 const uint16_t glyph_index = i - 1; // index in the map is 0-origin. |
| 879 const CFFIndex *local_subrs_to_use = NULL; |
| 880 if (!SelectLocalSubr(fd_select, |
| 881 local_subrs_per_font, |
| 882 local_subrs, |
| 883 glyph_index, |
| 884 &local_subrs_to_use)) { |
| 885 return OTS_FAILURE(); |
| 886 } |
| 887 // If |local_subrs_to_use| is still NULL, use an empty one. |
| 888 CFFIndex default_empty_subrs; |
| 889 if (!local_subrs_to_use){ |
| 890 local_subrs_to_use = &default_empty_subrs; |
| 891 } |
| 892 |
| 893 // Check a charstring for the |i|-th glyph. |
| 894 std::stack<int32_t> argument_stack; |
| 895 bool found_endchar = false; |
| 896 bool found_width = false; |
| 897 size_t num_stems = 0; |
| 898 if (!ExecuteType2CharString(file, |
| 899 0 /* initial call_depth is zero */, |
| 900 global_subrs_index, *local_subrs_to_use, |
| 901 cff_table, &char_string, &argument_stack, |
| 902 &found_endchar, &found_width, &num_stems)) { |
| 903 return OTS_FAILURE(); |
| 904 } |
| 905 if (!found_endchar) { |
| 906 return OTS_FAILURE(); |
| 907 } |
| 908 } |
| 909 return true; |
| 910 } |
| 911 |
| 912 } // namespace ots |
| 913 |
| 914 #undef TABLE_NAME |
OLD | NEW |