gfx/ots/src/cff.cc

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "cff.h"
michael@0 6
michael@0 7 #include <cstring>
michael@0 8 #include <utility>
michael@0 9 #include <vector>
michael@0 10
michael@0 11 #include "cff_type2_charstring.h"
michael@0 12
michael@0 13 // CFF - PostScript font program (Compact Font Format) table
michael@0 14 // http://www.microsoft.com/typography/otspec/cff.htm
michael@0 15 // http://www.microsoft.com/typography/otspec/cffspec.htm
michael@0 16
michael@0 17 #define TABLE_NAME "CFF"
michael@0 18
michael@0 19 namespace {
michael@0 20
michael@0 21 enum DICT_OPERAND_TYPE {
michael@0 22 DICT_OPERAND_INTEGER,
michael@0 23 DICT_OPERAND_REAL,
michael@0 24 DICT_OPERATOR,
michael@0 25 };
michael@0 26
michael@0 27 enum DICT_DATA_TYPE {
michael@0 28 DICT_DATA_TOPLEVEL,
michael@0 29 DICT_DATA_FDARRAY,
michael@0 30 };
michael@0 31
michael@0 32 enum FONT_FORMAT {
michael@0 33 FORMAT_UNKNOWN,
michael@0 34 FORMAT_CID_KEYED,
michael@0 35 FORMAT_OTHER, // Including synthetic fonts
michael@0 36 };
michael@0 37
michael@0 38 // see Appendix. A
michael@0 39 const size_t kNStdString = 390;
michael@0 40
michael@0 41 bool ReadOffset(ots::Buffer *table, uint8_t off_size, uint32_t *offset) {
michael@0 42 if (off_size > 4) {
michael@0 43 return OTS_FAILURE();
michael@0 44 }
michael@0 45
michael@0 46 uint32_t tmp32 = 0;
michael@0 47 for (unsigned i = 0; i < off_size; ++i) {
michael@0 48 uint8_t tmp8 = 0;
michael@0 49 if (!table->ReadU8(&tmp8)) {
michael@0 50 return OTS_FAILURE();
michael@0 51 }
michael@0 52 tmp32 <<= 8;
michael@0 53 tmp32 += tmp8;
michael@0 54 }
michael@0 55 *offset = tmp32;
michael@0 56 return true;
michael@0 57 }
michael@0 58
michael@0 59 bool ParseIndex(ots::Buffer *table, ots::CFFIndex *index) {
michael@0 60 index->off_size = 0;
michael@0 61 index->offsets.clear();
michael@0 62
michael@0 63 if (!table->ReadU16(&(index->count))) {
michael@0 64 return OTS_FAILURE();
michael@0 65 }
michael@0 66 if (index->count == 0) {
michael@0 67 // An empty INDEX.
michael@0 68 index->offset_to_next = table->offset();
michael@0 69 return true;
michael@0 70 }
michael@0 71
michael@0 72 if (!table->ReadU8(&(index->off_size))) {
michael@0 73 return OTS_FAILURE();
michael@0 74 }
michael@0 75 if ((index->off_size == 0) ||
michael@0 76 (index->off_size > 4)) {
michael@0 77 return OTS_FAILURE();
michael@0 78 }
michael@0 79
michael@0 80 const size_t array_size = (index->count + 1) * index->off_size;
michael@0 81 // less than ((64k + 1) * 4), thus does not overflow.
michael@0 82 const size_t object_data_offset = table->offset() + array_size;
michael@0 83 // does not overflow too, since offset() <= 1GB.
michael@0 84
michael@0 85 if (object_data_offset >= table->length()) {
michael@0 86 return OTS_FAILURE();
michael@0 87 }
michael@0 88
michael@0 89 for (unsigned i = 0; i <= index->count; ++i) { // '<=' is not a typo.
michael@0 90 uint32_t rel_offset = 0;
michael@0 91 if (!ReadOffset(table, index->off_size, &rel_offset)) {
michael@0 92 return OTS_FAILURE();
michael@0 93 }
michael@0 94 if (rel_offset < 1) {
michael@0 95 return OTS_FAILURE();
michael@0 96 }
michael@0 97 if (i == 0 && rel_offset != 1) {
michael@0 98 return OTS_FAILURE();
michael@0 99 }
michael@0 100
michael@0 101 if (rel_offset > table->length()) {
michael@0 102 return OTS_FAILURE();
michael@0 103 }
michael@0 104
michael@0 105 // does not underflow.
michael@0 106 if (object_data_offset > table->length() - (rel_offset - 1)) {
michael@0 107 return OTS_FAILURE();
michael@0 108 }
michael@0 109
michael@0 110 index->offsets.push_back(
michael@0 111 object_data_offset + (rel_offset - 1)); // less than length(), 1GB.
michael@0 112 }
michael@0 113
michael@0 114 for (unsigned i = 1; i < index->offsets.size(); ++i) {
michael@0 115 // We allow consecutive identical offsets here for zero-length strings.
michael@0 116 // See http://crbug.com/69341 for more details.
michael@0 117 if (index->offsets[i] < index->offsets[i - 1]) {
michael@0 118 return OTS_FAILURE();
michael@0 119 }
michael@0 120 }
michael@0 121
michael@0 122 index->offset_to_next = index->offsets.back();
michael@0 123 return true;
michael@0 124 }
michael@0 125
michael@0 126 bool ParseNameData(
michael@0 127 ots::Buffer *table, const ots::CFFIndex &index, std::string* out_name) {
michael@0 128 uint8_t name[256] = {0};
michael@0 129 if (index.offsets.size() == 0) { // just in case.
michael@0 130 return OTS_FAILURE();
michael@0 131 }
michael@0 132 for (unsigned i = 1; i < index.offsets.size(); ++i) {
michael@0 133 const size_t length = index.offsets[i] - index.offsets[i - 1];
michael@0 134 // font names should be no longer than 127 characters.
michael@0 135 if (length > 127) {
michael@0 136 return OTS_FAILURE();
michael@0 137 }
michael@0 138
michael@0 139 table->set_offset(index.offsets[i - 1]);
michael@0 140 if (!table->Read(name, length)) {
michael@0 141 return OTS_FAILURE();
michael@0 142 }
michael@0 143
michael@0 144 for (size_t j = 0; j < length; ++j) {
michael@0 145 // setting the first byte to NUL is allowed.
michael@0 146 if (j == 0 && name[j] == 0) continue;
michael@0 147 // non-ASCII characters are not recommended (except the first character).
michael@0 148 if (name[j] < 33 || name[j] > 126) {
michael@0 149 return OTS_FAILURE();
michael@0 150 }
michael@0 151 // [, ], ... are not allowed.
michael@0 152 if (std::strchr("[](){}<>/% ", name[j])) {
michael@0 153 return OTS_FAILURE();
michael@0 154 }
michael@0 155 }
michael@0 156 }
michael@0 157
michael@0 158 *out_name = reinterpret_cast<char *>(name);
michael@0 159 return true;
michael@0 160 }
michael@0 161
michael@0 162 bool CheckOffset(const std::pair<uint32_t, DICT_OPERAND_TYPE>& operand,
michael@0 163 size_t table_length) {
michael@0 164 if (operand.second != DICT_OPERAND_INTEGER) {
michael@0 165 return OTS_FAILURE();
michael@0 166 }
michael@0 167 if (operand.first >= table_length) {
michael@0 168 return OTS_FAILURE();
michael@0 169 }
michael@0 170 return true;
michael@0 171 }
michael@0 172
michael@0 173 bool CheckSid(const std::pair<uint32_t, DICT_OPERAND_TYPE>& operand,
michael@0 174 size_t sid_max) {
michael@0 175 if (operand.second != DICT_OPERAND_INTEGER) {
michael@0 176 return OTS_FAILURE();
michael@0 177 }
michael@0 178 if (operand.first > sid_max) {
michael@0 179 return OTS_FAILURE();
michael@0 180 }
michael@0 181 return true;
michael@0 182 }
michael@0 183
michael@0 184 bool ParseDictDataBcd(
michael@0 185 ots::Buffer *table,
michael@0 186 std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
michael@0 187 bool read_decimal_point = false;
michael@0 188 bool read_e = false;
michael@0 189
michael@0 190 uint8_t nibble = 0;
michael@0 191 size_t count = 0;
michael@0 192 while (true) {
michael@0 193 if (!table->ReadU8(&nibble)) {
michael@0 194 return OTS_FAILURE();
michael@0 195 }
michael@0 196 if ((nibble & 0xf0) == 0xf0) {
michael@0 197 if ((nibble & 0xf) == 0xf) {
michael@0 198 // TODO(yusukes): would be better to store actual double value,
michael@0 199 // rather than the dummy integer.
michael@0 200 operands->push_back(std::make_pair(static_cast<uint32_t>(0),
michael@0 201 DICT_OPERAND_REAL));
michael@0 202 return true;
michael@0 203 }
michael@0 204 return OTS_FAILURE();
michael@0 205 }
michael@0 206 if ((nibble & 0x0f) == 0x0f) {
michael@0 207 operands->push_back(std::make_pair(static_cast<uint32_t>(0),
michael@0 208 DICT_OPERAND_REAL));
michael@0 209 return true;
michael@0 210 }
michael@0 211
michael@0 212 // check number format
michael@0 213 uint8_t nibbles[2];
michael@0 214 nibbles[0] = (nibble & 0xf0) >> 8;
michael@0 215 nibbles[1] = (nibble & 0x0f);
michael@0 216 for (unsigned i = 0; i < 2; ++i) {
michael@0 217 if (nibbles[i] == 0xd) { // reserved number
michael@0 218 return OTS_FAILURE();
michael@0 219 }
michael@0 220 if ((nibbles[i] == 0xe) && // minus
michael@0 221 ((count > 0) || (i > 0))) {
michael@0 222 return OTS_FAILURE(); // minus sign should be the first character.
michael@0 223 }
michael@0 224 if (nibbles[i] == 0xa) { // decimal point
michael@0 225 if (!read_decimal_point) {
michael@0 226 read_decimal_point = true;
michael@0 227 } else {
michael@0 228 return OTS_FAILURE(); // two or more points.
michael@0 229 }
michael@0 230 }
michael@0 231 if ((nibbles[i] == 0xb) || // E+
michael@0 232 (nibbles[i] == 0xc)) { // E-
michael@0 233 if (!read_e) {
michael@0 234 read_e = true;
michael@0 235 } else {
michael@0 236 return OTS_FAILURE(); // two or more E's.
michael@0 237 }
michael@0 238 }
michael@0 239 }
michael@0 240 ++count;
michael@0 241 }
michael@0 242 }
michael@0 243
michael@0 244 bool ParseDictDataEscapedOperator(
michael@0 245 ots::Buffer *table,
michael@0 246 std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
michael@0 247 uint8_t op = 0;
michael@0 248 if (!table->ReadU8(&op)) {
michael@0 249 return OTS_FAILURE();
michael@0 250 }
michael@0 251
michael@0 252 if ((op <= 14) ||
michael@0 253 (op >= 17 && op <= 23) ||
michael@0 254 (op >= 30 && op <= 38)) {
michael@0 255 operands->push_back(std::make_pair((12U << 8) + op, DICT_OPERATOR));
michael@0 256 return true;
michael@0 257 }
michael@0 258
michael@0 259 // reserved area.
michael@0 260 return OTS_FAILURE();
michael@0 261 }
michael@0 262
michael@0 263 bool ParseDictDataNumber(
michael@0 264 ots::Buffer *table, uint8_t b0,
michael@0 265 std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
michael@0 266 uint8_t b1 = 0;
michael@0 267 uint8_t b2 = 0;
michael@0 268 uint8_t b3 = 0;
michael@0 269 uint8_t b4 = 0;
michael@0 270
michael@0 271 switch (b0) {
michael@0 272 case 28: // shortint
michael@0 273 if (!table->ReadU8(&b1) ||
michael@0 274 !table->ReadU8(&b2)) {
michael@0 275 return OTS_FAILURE();
michael@0 276 }
michael@0 277 operands->push_back(std::make_pair(
michael@0 278 static_cast<uint32_t>((b1 << 8) + b2), DICT_OPERAND_INTEGER));
michael@0 279 return true;
michael@0 280
michael@0 281 case 29: // longint
michael@0 282 if (!table->ReadU8(&b1) ||
michael@0 283 !table->ReadU8(&b2) ||
michael@0 284 !table->ReadU8(&b3) ||
michael@0 285 !table->ReadU8(&b4)) {
michael@0 286 return OTS_FAILURE();
michael@0 287 }
michael@0 288 operands->push_back(std::make_pair(
michael@0 289 static_cast<uint32_t>((b1 << 24) + (b2 << 16) + (b3 << 8) + b4),
michael@0 290 DICT_OPERAND_INTEGER));
michael@0 291 return true;
michael@0 292
michael@0 293 case 30: // binary coded decimal
michael@0 294 return ParseDictDataBcd(table, operands);
michael@0 295
michael@0 296 default:
michael@0 297 break;
michael@0 298 }
michael@0 299
michael@0 300 uint32_t result;
michael@0 301 if (b0 >=32 && b0 <=246) {
michael@0 302 result = b0 - 139;
michael@0 303 } else if (b0 >=247 && b0 <= 250) {
michael@0 304 if (!table->ReadU8(&b1)) {
michael@0 305 return OTS_FAILURE();
michael@0 306 }
michael@0 307 result = (b0 - 247) * 256 + b1 + 108;
michael@0 308 } else if (b0 >= 251 && b0 <= 254) {
michael@0 309 if (!table->ReadU8(&b1)) {
michael@0 310 return OTS_FAILURE();
michael@0 311 }
michael@0 312 result = -(b0 - 251) * 256 + b1 - 108;
michael@0 313 } else {
michael@0 314 return OTS_FAILURE();
michael@0 315 }
michael@0 316
michael@0 317 operands->push_back(std::make_pair(result, DICT_OPERAND_INTEGER));
michael@0 318 return true;
michael@0 319 }
michael@0 320
michael@0 321 bool ParseDictDataReadNext(
michael@0 322 ots::Buffer *table,
michael@0 323 std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
michael@0 324 uint8_t op = 0;
michael@0 325 if (!table->ReadU8(&op)) {
michael@0 326 return OTS_FAILURE();
michael@0 327 }
michael@0 328 if (op <= 21) {
michael@0 329 if (op == 12) {
michael@0 330 return ParseDictDataEscapedOperator(table, operands);
michael@0 331 }
michael@0 332 operands->push_back(std::make_pair(
michael@0 333 static_cast<uint32_t>(op), DICT_OPERATOR));
michael@0 334 return true;
michael@0 335 } else if (op <= 27 || op == 31 || op == 255) {
michael@0 336 // reserved area.
michael@0 337 return OTS_FAILURE();
michael@0 338 }
michael@0 339
michael@0 340 return ParseDictDataNumber(table, op, operands);
michael@0 341 }
michael@0 342
michael@0 343 bool ParsePrivateDictData(
michael@0 344 const uint8_t *data,
michael@0 345 size_t table_length, size_t offset, size_t dict_length,
michael@0 346 DICT_DATA_TYPE type, ots::OpenTypeCFF *out_cff) {
michael@0 347 ots::Buffer table(data + offset, dict_length);
michael@0 348 std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
michael@0 349
michael@0 350 // Since a Private DICT for FDArray might not have a Local Subr (e.g. Hiragino
michael@0 351 // Kaku Gothic Std W8), we create an empty Local Subr here to match the size
michael@0 352 // of FDArray the size of |local_subrs_per_font|.
michael@0 353 if (type == DICT_DATA_FDARRAY) {
michael@0 354 out_cff->local_subrs_per_font.push_back(new ots::CFFIndex);
michael@0 355 }
michael@0 356
michael@0 357 while (table.offset() < dict_length) {
michael@0 358 if (!ParseDictDataReadNext(&table, &operands)) {
michael@0 359 return OTS_FAILURE();
michael@0 360 }
michael@0 361 if (operands.empty()) {
michael@0 362 return OTS_FAILURE();
michael@0 363 }
michael@0 364 if (operands.size() > 48) {
michael@0 365 // An operator may be preceded by up to a maximum of 48 operands.
michael@0 366 return OTS_FAILURE();
michael@0 367 }
michael@0 368 if (operands.back().second != DICT_OPERATOR) {
michael@0 369 continue;
michael@0 370 }
michael@0 371
michael@0 372 // got operator
michael@0 373 const uint32_t op = operands.back().first;
michael@0 374 operands.pop_back();
michael@0 375
michael@0 376 switch (op) {
michael@0 377 // array
michael@0 378 case 6: // BlueValues
michael@0 379 case 7: // OtherBlues
michael@0 380 case 8: // FamilyBlues
michael@0 381 case 9: // FamilyOtherBlues
michael@0 382 case (12U << 8) + 12: // StemSnapH (delta)
michael@0 383 case (12U << 8) + 13: // StemSnapV (delta)
michael@0 384 if (operands.empty()) {
michael@0 385 return OTS_FAILURE();
michael@0 386 }
michael@0 387 break;
michael@0 388
michael@0 389 // number
michael@0 390 case 10: // StdHW
michael@0 391 case 11: // StdVW
michael@0 392 case 20: // defaultWidthX
michael@0 393 case 21: // nominalWidthX
michael@0 394 case (12U << 8) + 9: // BlueScale
michael@0 395 case (12U << 8) + 10: // BlueShift
michael@0 396 case (12U << 8) + 11: // BlueFuzz
michael@0 397 case (12U << 8) + 17: // LanguageGroup
michael@0 398 case (12U << 8) + 18: // ExpansionFactor
michael@0 399 case (12U << 8) + 19: // initialRandomSeed
michael@0 400 if (operands.size() != 1) {
michael@0 401 return OTS_FAILURE();
michael@0 402 }
michael@0 403 break;
michael@0 404
michael@0 405 // Local Subrs INDEX, offset(self)
michael@0 406 case 19: {
michael@0 407 if (operands.size() != 1) {
michael@0 408 return OTS_FAILURE();
michael@0 409 }
michael@0 410 if (operands.back().second != DICT_OPERAND_INTEGER) {
michael@0 411 return OTS_FAILURE();
michael@0 412 }
michael@0 413 if (operands.back().first >= 1024 * 1024 * 1024) {
michael@0 414 return OTS_FAILURE();
michael@0 415 }
michael@0 416 if (operands.back().first + offset >= table_length) {
michael@0 417 return OTS_FAILURE();
michael@0 418 }
michael@0 419 // parse "16. Local Subrs INDEX"
michael@0 420 ots::Buffer cff_table(data, table_length);
michael@0 421 cff_table.set_offset(operands.back().first + offset);
michael@0 422 ots::CFFIndex *local_subrs_index = NULL;
michael@0 423 if (type == DICT_DATA_FDARRAY) {
michael@0 424 if (out_cff->local_subrs_per_font.empty()) {
michael@0 425 return OTS_FAILURE(); // not reached.
michael@0 426 }
michael@0 427 local_subrs_index = out_cff->local_subrs_per_font.back();
michael@0 428 } else { // type == DICT_DATA_TOPLEVEL
michael@0 429 if (out_cff->local_subrs) {
michael@0 430 return OTS_FAILURE(); // two or more local_subrs?
michael@0 431 }
michael@0 432 local_subrs_index = new ots::CFFIndex;
michael@0 433 out_cff->local_subrs = local_subrs_index;
michael@0 434 }
michael@0 435 if (!ParseIndex(&cff_table, local_subrs_index)) {
michael@0 436 return OTS_FAILURE();
michael@0 437 }
michael@0 438 break;
michael@0 439 }
michael@0 440
michael@0 441 // boolean
michael@0 442 case (12U << 8) + 14: // ForceBold
michael@0 443 if (operands.size() != 1) {
michael@0 444 return OTS_FAILURE();
michael@0 445 }
michael@0 446 if (operands.back().second != DICT_OPERAND_INTEGER) {
michael@0 447 return OTS_FAILURE();
michael@0 448 }
michael@0 449 if (operands.back().first >= 2) {
michael@0 450 return OTS_FAILURE();
michael@0 451 }
michael@0 452 break;
michael@0 453
michael@0 454 default:
michael@0 455 return OTS_FAILURE();
michael@0 456 }
michael@0 457 operands.clear();
michael@0 458 }
michael@0 459
michael@0 460 return true;
michael@0 461 }
michael@0 462
michael@0 463 bool ParseDictData(const uint8_t *data, size_t table_length,
michael@0 464 const ots::CFFIndex &index, size_t sid_max,
michael@0 465 DICT_DATA_TYPE type, ots::OpenTypeCFF *out_cff) {
michael@0 466 for (unsigned i = 1; i < index.offsets.size(); ++i) {
michael@0 467 if (type == DICT_DATA_TOPLEVEL) {
michael@0 468 out_cff->char_strings_array.push_back(new ots::CFFIndex);
michael@0 469 }
michael@0 470 size_t dict_length = index.offsets[i] - index.offsets[i - 1];
michael@0 471 ots::Buffer table(data + index.offsets[i - 1], dict_length);
michael@0 472
michael@0 473 std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
michael@0 474
michael@0 475 FONT_FORMAT font_format = FORMAT_UNKNOWN;
michael@0 476 bool have_ros = false;
michael@0 477 size_t glyphs = 0;
michael@0 478 size_t charset_offset = 0;
michael@0 479
michael@0 480 while (table.offset() < dict_length) {
michael@0 481 if (!ParseDictDataReadNext(&table, &operands)) {
michael@0 482 return OTS_FAILURE();
michael@0 483 }
michael@0 484 if (operands.empty()) {
michael@0 485 return OTS_FAILURE();
michael@0 486 }
michael@0 487 if (operands.size() > 48) {
michael@0 488 // An operator may be preceded by up to a maximum of 48 operands.
michael@0 489 return OTS_FAILURE();
michael@0 490 }
michael@0 491 if (operands.back().second != DICT_OPERATOR) continue;
michael@0 492
michael@0 493 // got operator
michael@0 494 const uint32_t op = operands.back().first;
michael@0 495 operands.pop_back();
michael@0 496
michael@0 497 switch (op) {
michael@0 498 // SID
michael@0 499 case 0: // version
michael@0 500 case 1: // Notice
michael@0 501 case 2: // Copyright
michael@0 502 case 3: // FullName
michael@0 503 case 4: // FamilyName
michael@0 504 case (12U << 8) + 0: // Copyright
michael@0 505 case (12U << 8) + 21: // PostScript
michael@0 506 case (12U << 8) + 22: // BaseFontName
michael@0 507 case (12U << 8) + 38: // FontName
michael@0 508 if (operands.size() != 1) {
michael@0 509 return OTS_FAILURE();
michael@0 510 }
michael@0 511 if (!CheckSid(operands.back(), sid_max)) {
michael@0 512 return OTS_FAILURE();
michael@0 513 }
michael@0 514 break;
michael@0 515
michael@0 516 // array
michael@0 517 case 5: // FontBBox
michael@0 518 case 14: // XUID
michael@0 519 case (12U << 8) + 7: // FontMatrix
michael@0 520 case (12U << 8) + 23: // BaseFontBlend (delta)
michael@0 521 if (operands.empty()) {
michael@0 522 return OTS_FAILURE();
michael@0 523 }
michael@0 524 break;
michael@0 525
michael@0 526 // number
michael@0 527 case 13: // UniqueID
michael@0 528 case (12U << 8) + 2: // ItalicAngle
michael@0 529 case (12U << 8) + 3: // UnderlinePosition
michael@0 530 case (12U << 8) + 4: // UnderlineThickness
michael@0 531 case (12U << 8) + 5: // PaintType
michael@0 532 case (12U << 8) + 8: // StrokeWidth
michael@0 533 case (12U << 8) + 20: // SyntheticBase
michael@0 534 if (operands.size() != 1) {
michael@0 535 return OTS_FAILURE();
michael@0 536 }
michael@0 537 break;
michael@0 538 case (12U << 8) + 31: // CIDFontVersion
michael@0 539 case (12U << 8) + 32: // CIDFontRevision
michael@0 540 case (12U << 8) + 33: // CIDFontType
michael@0 541 case (12U << 8) + 34: // CIDCount
michael@0 542 case (12U << 8) + 35: // UIDBase
michael@0 543 if (operands.size() != 1) {
michael@0 544 return OTS_FAILURE();
michael@0 545 }
michael@0 546 if (font_format != FORMAT_CID_KEYED) {
michael@0 547 return OTS_FAILURE();
michael@0 548 }
michael@0 549 break;
michael@0 550 case (12U << 8) + 6: // CharstringType
michael@0 551 if (operands.size() != 1) {
michael@0 552 return OTS_FAILURE();
michael@0 553 }
michael@0 554 if(operands.back().second != DICT_OPERAND_INTEGER) {
michael@0 555 return OTS_FAILURE();
michael@0 556 }
michael@0 557 if (operands.back().first != 2) {
michael@0 558 // We only support the "Type 2 Charstring Format."
michael@0 559 // TODO(yusukes): Support Type 1 format? Is that still in use?
michael@0 560 return OTS_FAILURE();
michael@0 561 }
michael@0 562 break;
michael@0 563
michael@0 564 // boolean
michael@0 565 case (12U << 8) + 1: // isFixedPitch
michael@0 566 if (operands.size() != 1) {
michael@0 567 return OTS_FAILURE();
michael@0 568 }
michael@0 569 if (operands.back().second != DICT_OPERAND_INTEGER) {
michael@0 570 return OTS_FAILURE();
michael@0 571 }
michael@0 572 if (operands.back().first >= 2) {
michael@0 573 return OTS_FAILURE();
michael@0 574 }
michael@0 575 break;
michael@0 576
michael@0 577 // offset(0)
michael@0 578 case 15: // charset
michael@0 579 if (operands.size() != 1) {
michael@0 580 return OTS_FAILURE();
michael@0 581 }
michael@0 582 if (operands.back().first <= 2) {
michael@0 583 // predefined charset, ISOAdobe, Expert or ExpertSubset, is used.
michael@0 584 break;
michael@0 585 }
michael@0 586 if (!CheckOffset(operands.back(), table_length)) {
michael@0 587 return OTS_FAILURE();
michael@0 588 }
michael@0 589 if (charset_offset) {
michael@0 590 return OTS_FAILURE(); // multiple charset tables?
michael@0 591 }
michael@0 592 charset_offset = operands.back().first;
michael@0 593 break;
michael@0 594
michael@0 595 case 16: { // Encoding
michael@0 596 if (operands.size() != 1) {
michael@0 597 return OTS_FAILURE();
michael@0 598 }
michael@0 599 if (operands.back().first <= 1) {
michael@0 600 break; // predefined encoding, "Standard" or "Expert", is used.
michael@0 601 }
michael@0 602 if (!CheckOffset(operands.back(), table_length)) {
michael@0 603 return OTS_FAILURE();
michael@0 604 }
michael@0 605
michael@0 606 // parse sub dictionary INDEX.
michael@0 607 ots::Buffer cff_table(data, table_length);
michael@0 608 cff_table.set_offset(operands.back().first);
michael@0 609 uint8_t format = 0;
michael@0 610 if (!cff_table.ReadU8(&format)) {
michael@0 611 return OTS_FAILURE();
michael@0 612 }
michael@0 613 if (format & 0x80) {
michael@0 614 // supplemental encoding is not supported at the moment.
michael@0 615 return OTS_FAILURE();
michael@0 616 }
michael@0 617 // TODO(yusukes): support & parse supplemental encoding tables.
michael@0 618 break;
michael@0 619 }
michael@0 620
michael@0 621 case 17: { // CharStrings
michael@0 622 if (type != DICT_DATA_TOPLEVEL) {
michael@0 623 return OTS_FAILURE();
michael@0 624 }
michael@0 625 if (operands.size() != 1) {
michael@0 626 return OTS_FAILURE();
michael@0 627 }
michael@0 628 if (!CheckOffset(operands.back(), table_length)) {
michael@0 629 return OTS_FAILURE();
michael@0 630 }
michael@0 631 // parse "14. CharStrings INDEX"
michael@0 632 ots::Buffer cff_table(data, table_length);
michael@0 633 cff_table.set_offset(operands.back().first);
michael@0 634 ots::CFFIndex *charstring_index = out_cff->char_strings_array.back();
michael@0 635 if (!ParseIndex(&cff_table, charstring_index)) {
michael@0 636 return OTS_FAILURE();
michael@0 637 }
michael@0 638 if (charstring_index->count < 2) {
michael@0 639 return OTS_FAILURE();
michael@0 640 }
michael@0 641 if (glyphs) {
michael@0 642 return OTS_FAILURE(); // multiple charstring tables?
michael@0 643 }
michael@0 644 glyphs = charstring_index->count;
michael@0 645 break;
michael@0 646 }
michael@0 647
michael@0 648 case (12U << 8) + 36: { // FDArray
michael@0 649 if (type != DICT_DATA_TOPLEVEL) {
michael@0 650 return OTS_FAILURE();
michael@0 651 }
michael@0 652 if (operands.size() != 1) {
michael@0 653 return OTS_FAILURE();
michael@0 654 }
michael@0 655 if (!CheckOffset(operands.back(), table_length)) {
michael@0 656 return OTS_FAILURE();
michael@0 657 }
michael@0 658
michael@0 659 // parse sub dictionary INDEX.
michael@0 660 ots::Buffer cff_table(data, table_length);
michael@0 661 cff_table.set_offset(operands.back().first);
michael@0 662 ots::CFFIndex sub_dict_index;
michael@0 663 if (!ParseIndex(&cff_table, &sub_dict_index)) {
michael@0 664 return OTS_FAILURE();
michael@0 665 }
michael@0 666 if (!ParseDictData(data, table_length,
michael@0 667 sub_dict_index, sid_max, DICT_DATA_FDARRAY,
michael@0 668 out_cff)) {
michael@0 669 return OTS_FAILURE();
michael@0 670 }
michael@0 671 if (out_cff->font_dict_length != 0) {
michael@0 672 return OTS_FAILURE(); // two or more FDArray found.
michael@0 673 }
michael@0 674 out_cff->font_dict_length = sub_dict_index.count;
michael@0 675 break;
michael@0 676 }
michael@0 677
michael@0 678 case (12U << 8) + 37: { // FDSelect
michael@0 679 if (type != DICT_DATA_TOPLEVEL) {
michael@0 680 return OTS_FAILURE();
michael@0 681 }
michael@0 682 if (operands.size() != 1) {
michael@0 683 return OTS_FAILURE();
michael@0 684 }
michael@0 685 if (!CheckOffset(operands.back(), table_length)) {
michael@0 686 return OTS_FAILURE();
michael@0 687 }
michael@0 688
michael@0 689 // parse FDSelect data structure
michael@0 690 ots::Buffer cff_table(data, table_length);
michael@0 691 cff_table.set_offset(operands.back().first);
michael@0 692 uint8_t format = 0;
michael@0 693 if (!cff_table.ReadU8(&format)) {
michael@0 694 return OTS_FAILURE();
michael@0 695 }
michael@0 696 if (format == 0) {
michael@0 697 for (size_t j = 0; j < glyphs; ++j) {
michael@0 698 uint8_t fd_index = 0;
michael@0 699 if (!cff_table.ReadU8(&fd_index)) {
michael@0 700 return OTS_FAILURE();
michael@0 701 }
michael@0 702 (out_cff->fd_select)[j] = fd_index;
michael@0 703 }
michael@0 704 } else if (format == 3) {
michael@0 705 uint16_t n_ranges = 0;
michael@0 706 if (!cff_table.ReadU16(&n_ranges)) {
michael@0 707 return OTS_FAILURE();
michael@0 708 }
michael@0 709 if (n_ranges == 0) {
michael@0 710 return OTS_FAILURE();
michael@0 711 }
michael@0 712
michael@0 713 uint16_t last_gid = 0;
michael@0 714 uint8_t fd_index = 0;
michael@0 715 for (unsigned j = 0; j < n_ranges; ++j) {
michael@0 716 uint16_t first = 0; // GID
michael@0 717 if (!cff_table.ReadU16(&first)) {
michael@0 718 return OTS_FAILURE();
michael@0 719 }
michael@0 720
michael@0 721 // Sanity checks.
michael@0 722 if ((j == 0) && (first != 0)) {
michael@0 723 return OTS_FAILURE();
michael@0 724 }
michael@0 725 if ((j != 0) && (last_gid >= first)) {
michael@0 726 return OTS_FAILURE(); // not increasing order.
michael@0 727 }
michael@0 728
michael@0 729 // Copy the mapping to |out_cff->fd_select|.
michael@0 730 if (j != 0) {
michael@0 731 for (uint16_t k = last_gid; k < first; ++k) {
michael@0 732 if (!out_cff->fd_select.insert(
michael@0 733 std::make_pair(k, fd_index)).second) {
michael@0 734 return OTS_FAILURE();
michael@0 735 }
michael@0 736 }
michael@0 737 }
michael@0 738
michael@0 739 if (!cff_table.ReadU8(&fd_index)) {
michael@0 740 return OTS_FAILURE();
michael@0 741 }
michael@0 742 last_gid = first;
michael@0 743 // TODO(yusukes): check GID?
michael@0 744 }
michael@0 745 uint16_t sentinel = 0;
michael@0 746 if (!cff_table.ReadU16(&sentinel)) {
michael@0 747 return OTS_FAILURE();
michael@0 748 }
michael@0 749 if (last_gid >= sentinel) {
michael@0 750 return OTS_FAILURE();
michael@0 751 }
michael@0 752 for (uint16_t k = last_gid; k < sentinel; ++k) {
michael@0 753 if (!out_cff->fd_select.insert(
michael@0 754 std::make_pair(k, fd_index)).second) {
michael@0 755 return OTS_FAILURE();
michael@0 756 }
michael@0 757 }
michael@0 758 } else {
michael@0 759 // unknown format
michael@0 760 return OTS_FAILURE();
michael@0 761 }
michael@0 762 break;
michael@0 763 }
michael@0 764
michael@0 765 // Private DICT (2 * number)
michael@0 766 case 18: {
michael@0 767 if (operands.size() != 2) {
michael@0 768 return OTS_FAILURE();
michael@0 769 }
michael@0 770 if (operands.back().second != DICT_OPERAND_INTEGER) {
michael@0 771 return OTS_FAILURE();
michael@0 772 }
michael@0 773 const uint32_t private_offset = operands.back().first;
michael@0 774 operands.pop_back();
michael@0 775 if (operands.back().second != DICT_OPERAND_INTEGER) {
michael@0 776 return OTS_FAILURE();
michael@0 777 }
michael@0 778 const uint32_t private_length = operands.back().first;
michael@0 779 if (private_offset > table_length) {
michael@0 780 return OTS_FAILURE();
michael@0 781 }
michael@0 782 if (private_length >= table_length) {
michael@0 783 return OTS_FAILURE();
michael@0 784 }
michael@0 785 if (private_length + private_offset > table_length) {
michael@0 786 return OTS_FAILURE();
michael@0 787 }
michael@0 788 // parse "15. Private DICT Data"
michael@0 789 if (!ParsePrivateDictData(data, table_length,
michael@0 790 private_offset, private_length,
michael@0 791 type, out_cff)) {
michael@0 792 return OTS_FAILURE();
michael@0 793 }
michael@0 794 break;
michael@0 795 }
michael@0 796
michael@0 797 // ROS
michael@0 798 case (12U << 8) + 30:
michael@0 799 if (font_format != FORMAT_UNKNOWN) {
michael@0 800 return OTS_FAILURE();
michael@0 801 }
michael@0 802 font_format = FORMAT_CID_KEYED;
michael@0 803 if (operands.size() != 3) {
michael@0 804 return OTS_FAILURE();
michael@0 805 }
michael@0 806 // check SIDs
michael@0 807 operands.pop_back(); // ignore the first number.
michael@0 808 if (!CheckSid(operands.back(), sid_max)) {
michael@0 809 return OTS_FAILURE();
michael@0 810 }
michael@0 811 operands.pop_back();
michael@0 812 if (!CheckSid(operands.back(), sid_max)) {
michael@0 813 return OTS_FAILURE();
michael@0 814 }
michael@0 815 if (have_ros) {
michael@0 816 return OTS_FAILURE(); // multiple ROS tables?
michael@0 817 }
michael@0 818 have_ros = true;
michael@0 819 break;
michael@0 820
michael@0 821 default:
michael@0 822 return OTS_FAILURE();
michael@0 823 }
michael@0 824 operands.clear();
michael@0 825
michael@0 826 if (font_format == FORMAT_UNKNOWN) {
michael@0 827 font_format = FORMAT_OTHER;
michael@0 828 }
michael@0 829 }
michael@0 830
michael@0 831 // parse "13. Charsets"
michael@0 832 if (charset_offset) {
michael@0 833 ots::Buffer cff_table(data, table_length);
michael@0 834 cff_table.set_offset(charset_offset);
michael@0 835 uint8_t format = 0;
michael@0 836 if (!cff_table.ReadU8(&format)) {
michael@0 837 return OTS_FAILURE();
michael@0 838 }
michael@0 839 switch (format) {
michael@0 840 case 0:
michael@0 841 for (unsigned j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
michael@0 842 uint16_t sid = 0;
michael@0 843 if (!cff_table.ReadU16(&sid)) {
michael@0 844 return OTS_FAILURE();
michael@0 845 }
michael@0 846 if (!have_ros && (sid > sid_max)) {
michael@0 847 return OTS_FAILURE();
michael@0 848 }
michael@0 849 // TODO(yusukes): check CIDs when have_ros is true.
michael@0 850 }
michael@0 851 break;
michael@0 852
michael@0 853 case 1:
michael@0 854 case 2: {
michael@0 855 uint32_t total = 1; // .notdef is omitted.
michael@0 856 while (total < glyphs) {
michael@0 857 uint16_t sid = 0;
michael@0 858 if (!cff_table.ReadU16(&sid)) {
michael@0 859 return OTS_FAILURE();
michael@0 860 }
michael@0 861 if (!have_ros && (sid > sid_max)) {
michael@0 862 return OTS_FAILURE();
michael@0 863 }
michael@0 864 // TODO(yusukes): check CIDs when have_ros is true.
michael@0 865
michael@0 866 if (format == 1) {
michael@0 867 uint8_t left = 0;
michael@0 868 if (!cff_table.ReadU8(&left)) {
michael@0 869 return OTS_FAILURE();
michael@0 870 }
michael@0 871 total += (left + 1);
michael@0 872 } else {
michael@0 873 uint16_t left = 0;
michael@0 874 if (!cff_table.ReadU16(&left)) {
michael@0 875 return OTS_FAILURE();
michael@0 876 }
michael@0 877 total += (left + 1);
michael@0 878 }
michael@0 879 }
michael@0 880 break;
michael@0 881 }
michael@0 882
michael@0 883 default:
michael@0 884 return OTS_FAILURE();
michael@0 885 }
michael@0 886 }
michael@0 887 }
michael@0 888 return true;
michael@0 889 }
michael@0 890
michael@0 891 } // namespace
michael@0 892
michael@0 893 namespace ots {
michael@0 894
michael@0 895 bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
michael@0 896 Buffer table(data, length);
michael@0 897
michael@0 898 file->cff = new OpenTypeCFF;
michael@0 899 file->cff->data = data;
michael@0 900 file->cff->length = length;
michael@0 901 file->cff->font_dict_length = 0;
michael@0 902 file->cff->local_subrs = NULL;
michael@0 903
michael@0 904 // parse "6. Header" in the Adobe Compact Font Format Specification
michael@0 905 uint8_t major = 0;
michael@0 906 uint8_t minor = 0;
michael@0 907 uint8_t hdr_size = 0;
michael@0 908 uint8_t off_size = 0;
michael@0 909 if (!table.ReadU8(&major)) {
michael@0 910 return OTS_FAILURE();
michael@0 911 }
michael@0 912 if (!table.ReadU8(&minor)) {
michael@0 913 return OTS_FAILURE();
michael@0 914 }
michael@0 915 if (!table.ReadU8(&hdr_size)) {
michael@0 916 return OTS_FAILURE();
michael@0 917 }
michael@0 918 if (!table.ReadU8(&off_size)) {
michael@0 919 return OTS_FAILURE();
michael@0 920 }
michael@0 921 if ((off_size == 0) || (off_size > 4)) {
michael@0 922 return OTS_FAILURE();
michael@0 923 }
michael@0 924
michael@0 925 if ((major != 1) ||
michael@0 926 (minor != 0) ||
michael@0 927 (hdr_size != 4)) {
michael@0 928 return OTS_FAILURE();
michael@0 929 }
michael@0 930 if (hdr_size >= length) {
michael@0 931 return OTS_FAILURE();
michael@0 932 }
michael@0 933
michael@0 934 // parse "7. Name INDEX"
michael@0 935 table.set_offset(hdr_size);
michael@0 936 CFFIndex name_index;
michael@0 937 if (!ParseIndex(&table, &name_index)) {
michael@0 938 return OTS_FAILURE();
michael@0 939 }
michael@0 940 if (!ParseNameData(&table, name_index, &(file->cff->name))) {
michael@0 941 return OTS_FAILURE();
michael@0 942 }
michael@0 943
michael@0 944 // parse "8. Top DICT INDEX"
michael@0 945 table.set_offset(name_index.offset_to_next);
michael@0 946 CFFIndex top_dict_index;
michael@0 947 if (!ParseIndex(&table, &top_dict_index)) {
michael@0 948 return OTS_FAILURE();
michael@0 949 }
michael@0 950 if (name_index.count != top_dict_index.count) {
michael@0 951 return OTS_FAILURE();
michael@0 952 }
michael@0 953
michael@0 954 // parse "10. String INDEX"
michael@0 955 table.set_offset(top_dict_index.offset_to_next);
michael@0 956 CFFIndex string_index;
michael@0 957 if (!ParseIndex(&table, &string_index)) {
michael@0 958 return OTS_FAILURE();
michael@0 959 }
michael@0 960 if (string_index.count >= 65000 - kNStdString) {
michael@0 961 return OTS_FAILURE();
michael@0 962 }
michael@0 963
michael@0 964 const size_t sid_max = string_index.count + kNStdString;
michael@0 965 // string_index.count == 0 is allowed.
michael@0 966
michael@0 967 // parse "9. Top DICT Data"
michael@0 968 if (!ParseDictData(data, length, top_dict_index,
michael@0 969 sid_max, DICT_DATA_TOPLEVEL, file->cff)) {
michael@0 970 return OTS_FAILURE();
michael@0 971 }
michael@0 972
michael@0 973 // parse "16. Global Subrs INDEX"
michael@0 974 table.set_offset(string_index.offset_to_next);
michael@0 975 CFFIndex global_subrs_index;
michael@0 976 if (!ParseIndex(&table, &global_subrs_index)) {
michael@0 977 return OTS_FAILURE();
michael@0 978 }
michael@0 979
michael@0 980 // Check if all fd_index in FDSelect are valid.
michael@0 981 std::map<uint16_t, uint8_t>::const_iterator iter;
michael@0 982 std::map<uint16_t, uint8_t>::const_iterator end = file->cff->fd_select.end();
michael@0 983 for (iter = file->cff->fd_select.begin(); iter != end; ++iter) {
michael@0 984 if (iter->second >= file->cff->font_dict_length) {
michael@0 985 return OTS_FAILURE();
michael@0 986 }
michael@0 987 }
michael@0 988
michael@0 989 // Check if all charstrings (font hinting code for each glyph) are valid.
michael@0 990 for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
michael@0 991 if (!ValidateType2CharStringIndex(*(file->cff->char_strings_array.at(i)),
michael@0 992 global_subrs_index,
michael@0 993 file->cff->fd_select,
michael@0 994 file->cff->local_subrs_per_font,
michael@0 995 file->cff->local_subrs,
michael@0 996 &table)) {
michael@0 997 return OTS_FAILURE();
michael@0 998 }
michael@0 999 }
michael@0 1000
michael@0 1001 return true;
michael@0 1002 }
michael@0 1003
michael@0 1004 bool ots_cff_should_serialise(OpenTypeFile *file) {
michael@0 1005 return file->cff != NULL;
michael@0 1006 }
michael@0 1007
michael@0 1008 bool ots_cff_serialise(OTSStream *out, OpenTypeFile *file) {
michael@0 1009 // TODO(yusukes): would be better to transcode the data,
michael@0 1010 // rather than simple memcpy.
michael@0 1011 if (!out->Write(file->cff->data, file->cff->length)) {
michael@0 1012 return OTS_FAILURE();
michael@0 1013 }
michael@0 1014 return true;
michael@0 1015 }
michael@0 1016
michael@0 1017 void ots_cff_free(OpenTypeFile *file) {
michael@0 1018 if (file->cff) {
michael@0 1019 for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
michael@0 1020 delete (file->cff->char_strings_array)[i];
michael@0 1021 }
michael@0 1022 for (size_t i = 0; i < file->cff->local_subrs_per_font.size(); ++i) {
michael@0 1023 delete (file->cff->local_subrs_per_font)[i];
michael@0 1024 }
michael@0 1025 delete file->cff->local_subrs;
michael@0 1026 delete file->cff;
michael@0 1027 }
michael@0 1028 }
michael@0 1029
michael@0 1030 } // namespace ots

mercurial