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