1 /* 2 * Copyright © 2007,2008,2009 Red Hat, Inc. 3 * Copyright © 2012 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29 #ifndef HB_OPEN_FILE_HH 30 #define HB_OPEN_FILE_HH 31 32 #include "hb-open-type.hh" 33 #include "hb-ot-head-table.hh" 34 35 36 namespace OT { 37 38 39 /* 40 * 41 * The OpenType Font File 42 * 43 */ 44 45 46 /* 47 * Organization of an OpenType Font 48 */ 49 50 struct OpenTypeFontFile; 51 struct OffsetTable; 52 struct TTCHeader; 53 54 55 typedef struct TableRecord 56 { cmpOT::TableRecord57 int cmp (Tag t) const { return -t.cmp (tag); } 58 cmpOT::TableRecord59 static int cmp (const void *pa, const void *pb) 60 { 61 const TableRecord *a = (const TableRecord *) pa; 62 const TableRecord *b = (const TableRecord *) pb; 63 return b->cmp (a->tag); 64 } 65 sanitizeOT::TableRecord66 bool sanitize (hb_sanitize_context_t *c) const 67 { 68 TRACE_SANITIZE (this); 69 return_trace (c->check_struct (this)); 70 } 71 72 Tag tag; /* 4-byte identifier. */ 73 CheckSum checkSum; /* CheckSum for this table. */ 74 Offset32 offset; /* Offset from beginning of TrueType font 75 * file. */ 76 HBUINT32 length; /* Length of this table. */ 77 public: 78 DEFINE_SIZE_STATIC (16); 79 } OpenTypeTable; 80 81 typedef struct OffsetTable 82 { 83 friend struct OpenTypeFontFile; 84 get_table_countOT::OffsetTable85 unsigned int get_table_count () const { return tables.len; } get_tableOT::OffsetTable86 const TableRecord& get_table (unsigned int i) const 87 { return tables[i]; } get_table_tagsOT::OffsetTable88 unsigned int get_table_tags (unsigned int start_offset, 89 unsigned int *table_count, /* IN/OUT */ 90 hb_tag_t *table_tags /* OUT */) const 91 { 92 if (table_count) 93 { 94 if (start_offset >= tables.len) 95 *table_count = 0; 96 else 97 *table_count = MIN<unsigned int> (*table_count, tables.len - start_offset); 98 99 const TableRecord *sub_tables = tables.arrayZ + start_offset; 100 unsigned int count = *table_count; 101 for (unsigned int i = 0; i < count; i++) 102 table_tags[i] = sub_tables[i].tag; 103 } 104 return tables.len; 105 } find_table_indexOT::OffsetTable106 bool find_table_index (hb_tag_t tag, unsigned int *table_index) const 107 { 108 Tag t; 109 t.set (tag); 110 return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); 111 } get_table_by_tagOT::OffsetTable112 const TableRecord& get_table_by_tag (hb_tag_t tag) const 113 { 114 unsigned int table_index; 115 find_table_index (tag, &table_index); 116 return get_table (table_index); 117 } 118 119 public: 120 121 template <typename item_t> serializeOT::OffsetTable122 bool serialize (hb_serialize_context_t *c, 123 hb_tag_t sfnt_tag, 124 hb_array_t<item_t> items) 125 { 126 TRACE_SERIALIZE (this); 127 /* Alloc 12 for the OTHeader. */ 128 if (unlikely (!c->extend_min (*this))) return_trace (false); 129 /* Write sfntVersion (bytes 0..3). */ 130 sfnt_version.set (sfnt_tag); 131 /* Take space for numTables, searchRange, entrySelector, RangeShift 132 * and the TableRecords themselves. */ 133 if (unlikely (!tables.serialize (c, items.len))) return_trace (false); 134 135 const char *dir_end = (const char *) c->head; 136 HBUINT32 *checksum_adjustment = nullptr; 137 138 /* Write OffsetTables, alloc for and write actual table blobs. */ 139 for (unsigned int i = 0; i < tables.len; i++) 140 { 141 TableRecord &rec = tables.arrayZ[i]; 142 hb_blob_t *blob = items[i].blob; 143 rec.tag.set (items[i].tag); 144 rec.length.set (hb_blob_get_length (blob)); 145 rec.offset.serialize (c, this); 146 147 /* Allocate room for the table and copy it. */ 148 char *start = (char *) c->allocate_size<void> (rec.length); 149 if (unlikely (!start)) {return false;} 150 151 memcpy (start, hb_blob_get_data (blob, nullptr), rec.length); 152 153 /* 4-byte alignment. */ 154 c->align (4); 155 const char *end = (const char *) c->head; 156 157 if (items[i].tag == HB_OT_TAG_head && end - start >= head::static_size) 158 { 159 head *h = (head *) start; 160 checksum_adjustment = &h->checkSumAdjustment; 161 checksum_adjustment->set (0); 162 } 163 164 rec.checkSum.set_for_data (start, end - start); 165 } 166 167 tables.qsort (); 168 169 if (checksum_adjustment) 170 { 171 CheckSum checksum; 172 173 /* The following line is a slower version of the following block. */ 174 //checksum.set_for_data (this, (const char *) c->head - (const char *) this); 175 checksum.set_for_data (this, dir_end - (const char *) this); 176 for (unsigned int i = 0; i < items.len; i++) 177 { 178 TableRecord &rec = tables.arrayZ[i]; 179 checksum.set (checksum + rec.checkSum); 180 } 181 182 checksum_adjustment->set (0xB1B0AFBAu - checksum); 183 } 184 185 return_trace (true); 186 } 187 sanitizeOT::OffsetTable188 bool sanitize (hb_sanitize_context_t *c) const 189 { 190 TRACE_SANITIZE (this); 191 return_trace (c->check_struct (this) && tables.sanitize (c)); 192 } 193 194 protected: 195 Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */ 196 BinSearchArrayOf<TableRecord> 197 tables; 198 public: 199 DEFINE_SIZE_ARRAY (12, tables); 200 } OpenTypeFontFace; 201 202 203 /* 204 * TrueType Collections 205 */ 206 207 struct TTCHeaderVersion1 208 { 209 friend struct TTCHeader; 210 get_face_countOT::TTCHeaderVersion1211 unsigned int get_face_count () const { return table.len; } get_faceOT::TTCHeaderVersion1212 const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } 213 sanitizeOT::TTCHeaderVersion1214 bool sanitize (hb_sanitize_context_t *c) const 215 { 216 TRACE_SANITIZE (this); 217 return_trace (table.sanitize (c, this)); 218 } 219 220 protected: 221 Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ 222 FixedVersion<>version; /* Version of the TTC Header (1.0), 223 * 0x00010000u */ 224 LArrayOf<LOffsetTo<OffsetTable> > 225 table; /* Array of offsets to the OffsetTable for each font 226 * from the beginning of the file */ 227 public: 228 DEFINE_SIZE_ARRAY (12, table); 229 }; 230 231 struct TTCHeader 232 { 233 friend struct OpenTypeFontFile; 234 235 private: 236 get_face_countOT::TTCHeader237 unsigned int get_face_count () const 238 { 239 switch (u.header.version.major) { 240 case 2: /* version 2 is compatible with version 1 */ 241 case 1: return u.version1.get_face_count (); 242 default:return 0; 243 } 244 } get_faceOT::TTCHeader245 const OpenTypeFontFace& get_face (unsigned int i) const 246 { 247 switch (u.header.version.major) { 248 case 2: /* version 2 is compatible with version 1 */ 249 case 1: return u.version1.get_face (i); 250 default:return Null(OpenTypeFontFace); 251 } 252 } 253 sanitizeOT::TTCHeader254 bool sanitize (hb_sanitize_context_t *c) const 255 { 256 TRACE_SANITIZE (this); 257 if (unlikely (!u.header.version.sanitize (c))) return_trace (false); 258 switch (u.header.version.major) { 259 case 2: /* version 2 is compatible with version 1 */ 260 case 1: return_trace (u.version1.sanitize (c)); 261 default:return_trace (true); 262 } 263 } 264 265 protected: 266 union { 267 struct { 268 Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ 269 FixedVersion<>version; /* Version of the TTC Header (1.0 or 2.0), 270 * 0x00010000u or 0x00020000u */ 271 } header; 272 TTCHeaderVersion1 version1; 273 } u; 274 }; 275 276 /* 277 * Mac Resource Fork 278 * 279 * http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html 280 */ 281 282 struct ResourceRecord 283 { get_faceOT::ResourceRecord284 const OpenTypeFontFace & get_face (const void *data_base) const 285 { return CastR<OpenTypeFontFace> ((data_base+offset).arrayZ); } 286 sanitizeOT::ResourceRecord287 bool sanitize (hb_sanitize_context_t *c, 288 const void *data_base) const 289 { 290 TRACE_SANITIZE (this); 291 return_trace (c->check_struct (this) && 292 offset.sanitize (c, data_base) && 293 get_face (data_base).sanitize (c)); 294 } 295 296 protected: 297 HBUINT16 id; /* Resource ID. */ 298 HBINT16 nameOffset; /* Offset from beginning of resource name list 299 * to resource name, -1 means there is none. */ 300 HBUINT8 attrs; /* Resource attributes */ 301 OffsetTo<LArrayOf<HBUINT8>, HBUINT24, false> 302 offset; /* Offset from beginning of data block to 303 * data for this resource */ 304 HBUINT32 reserved; /* Reserved for handle to resource */ 305 public: 306 DEFINE_SIZE_STATIC (12); 307 }; 308 309 #define HB_TAG_sfnt HB_TAG ('s','f','n','t') 310 311 struct ResourceTypeRecord 312 { get_resource_countOT::ResourceTypeRecord313 unsigned int get_resource_count () const 314 { return tag == HB_TAG_sfnt ? resCountM1 + 1 : 0; } 315 is_sfntOT::ResourceTypeRecord316 bool is_sfnt () const { return tag == HB_TAG_sfnt; } 317 get_resource_recordOT::ResourceTypeRecord318 const ResourceRecord& get_resource_record (unsigned int i, 319 const void *type_base) const 320 { return (type_base+resourcesZ).as_array (get_resource_count ())[i]; } 321 sanitizeOT::ResourceTypeRecord322 bool sanitize (hb_sanitize_context_t *c, 323 const void *type_base, 324 const void *data_base) const 325 { 326 TRACE_SANITIZE (this); 327 return_trace (c->check_struct (this) && 328 resourcesZ.sanitize (c, type_base, 329 get_resource_count (), 330 data_base)); 331 } 332 333 protected: 334 Tag tag; /* Resource type. */ 335 HBUINT16 resCountM1; /* Number of resources minus 1. */ 336 OffsetTo<UnsizedArrayOf<ResourceRecord>, HBUINT16, false> 337 resourcesZ; /* Offset from beginning of resource type list 338 * to reference item list for this type. */ 339 public: 340 DEFINE_SIZE_STATIC (8); 341 }; 342 343 struct ResourceMap 344 { get_face_countOT::ResourceMap345 unsigned int get_face_count () const 346 { 347 unsigned int count = get_type_count (); 348 for (unsigned int i = 0; i < count; i++) 349 { 350 const ResourceTypeRecord& type = get_type_record (i); 351 if (type.is_sfnt ()) 352 return type.get_resource_count (); 353 } 354 return 0; 355 } 356 get_faceOT::ResourceMap357 const OpenTypeFontFace& get_face (unsigned int idx, 358 const void *data_base) const 359 { 360 unsigned int count = get_type_count (); 361 for (unsigned int i = 0; i < count; i++) 362 { 363 const ResourceTypeRecord& type = get_type_record (i); 364 /* The check for idx < count is here because ResourceRecord is NOT null-safe. 365 * Because an offset of 0 there does NOT mean null. */ 366 if (type.is_sfnt () && idx < type.get_resource_count ()) 367 return type.get_resource_record (idx, &(this+typeList)).get_face (data_base); 368 } 369 return Null (OpenTypeFontFace); 370 } 371 sanitizeOT::ResourceMap372 bool sanitize (hb_sanitize_context_t *c, const void *data_base) const 373 { 374 TRACE_SANITIZE (this); 375 return_trace (c->check_struct (this) && 376 typeList.sanitize (c, this, 377 &(this+typeList), 378 data_base)); 379 } 380 381 private: get_type_countOT::ResourceMap382 unsigned int get_type_count () const { return (this+typeList).lenM1 + 1; } 383 get_type_recordOT::ResourceMap384 const ResourceTypeRecord& get_type_record (unsigned int i) const 385 { return (this+typeList)[i]; } 386 387 protected: 388 HBUINT8 reserved0[16]; /* Reserved for copy of resource header */ 389 HBUINT32 reserved1; /* Reserved for handle to next resource map */ 390 HBUINT16 resreved2; /* Reserved for file reference number */ 391 HBUINT16 attrs; /* Resource fork attribute */ 392 OffsetTo<ArrayOfM1<ResourceTypeRecord>, HBUINT16, false> 393 typeList; /* Offset from beginning of map to 394 * resource type list */ 395 Offset16 nameList; /* Offset from beginning of map to 396 * resource name list */ 397 public: 398 DEFINE_SIZE_STATIC (28); 399 }; 400 401 struct ResourceForkHeader 402 { get_face_countOT::ResourceForkHeader403 unsigned int get_face_count () const 404 { return (this+map).get_face_count (); } 405 get_faceOT::ResourceForkHeader406 const OpenTypeFontFace& get_face (unsigned int idx, 407 unsigned int *base_offset = nullptr) const 408 { 409 const OpenTypeFontFace &face = (this+map).get_face (idx, &(this+data)); 410 if (base_offset) 411 *base_offset = (const char *) &face - (const char *) this; 412 return face; 413 } 414 sanitizeOT::ResourceForkHeader415 bool sanitize (hb_sanitize_context_t *c) const 416 { 417 TRACE_SANITIZE (this); 418 return_trace (c->check_struct (this) && 419 data.sanitize (c, this, dataLen) && 420 map.sanitize (c, this, &(this+data))); 421 } 422 423 protected: 424 LOffsetTo<UnsizedArrayOf<HBUINT8>, false> 425 data; /* Offset from beginning of resource fork 426 * to resource data */ 427 LOffsetTo<ResourceMap, false> 428 map; /* Offset from beginning of resource fork 429 * to resource map */ 430 HBUINT32 dataLen; /* Length of resource data */ 431 HBUINT32 mapLen; /* Length of resource map */ 432 public: 433 DEFINE_SIZE_STATIC (16); 434 }; 435 436 /* 437 * OpenType Font File 438 */ 439 440 struct OpenTypeFontFile 441 { 442 enum { 443 CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */ 444 TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */ 445 TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */ 446 DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */ 447 TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */ 448 Typ1Tag = HB_TAG ('t','y','p','1') /* Obsolete Apple Type1 font in SFNT container */ 449 }; 450 get_tagOT::OpenTypeFontFile451 hb_tag_t get_tag () const { return u.tag; } 452 get_face_countOT::OpenTypeFontFile453 unsigned int get_face_count () const 454 { 455 switch (u.tag) { 456 case CFFTag: /* All the non-collection tags */ 457 case TrueTag: 458 case Typ1Tag: 459 case TrueTypeTag: return 1; 460 case TTCTag: return u.ttcHeader.get_face_count (); 461 case DFontTag: return u.rfHeader.get_face_count (); 462 default: return 0; 463 } 464 } get_faceOT::OpenTypeFontFile465 const OpenTypeFontFace& get_face (unsigned int i, unsigned int *base_offset = nullptr) const 466 { 467 if (base_offset) 468 *base_offset = 0; 469 switch (u.tag) { 470 /* Note: for non-collection SFNT data we ignore index. This is because 471 * Apple dfont container is a container of SFNT's. So each SFNT is a 472 * non-TTC, but the index is more than zero. */ 473 case CFFTag: /* All the non-collection tags */ 474 case TrueTag: 475 case Typ1Tag: 476 case TrueTypeTag: return u.fontFace; 477 case TTCTag: return u.ttcHeader.get_face (i); 478 case DFontTag: return u.rfHeader.get_face (i, base_offset); 479 default: return Null(OpenTypeFontFace); 480 } 481 } 482 483 template <typename item_t> serialize_singleOT::OpenTypeFontFile484 bool serialize_single (hb_serialize_context_t *c, 485 hb_tag_t sfnt_tag, 486 hb_array_t<item_t> items) 487 { 488 TRACE_SERIALIZE (this); 489 assert (sfnt_tag != TTCTag); 490 if (unlikely (!c->extend_min (*this))) return_trace (false); 491 return_trace (u.fontFace.serialize (c, sfnt_tag, items)); 492 } 493 sanitizeOT::OpenTypeFontFile494 bool sanitize (hb_sanitize_context_t *c) const 495 { 496 TRACE_SANITIZE (this); 497 if (unlikely (!u.tag.sanitize (c))) return_trace (false); 498 switch (u.tag) { 499 case CFFTag: /* All the non-collection tags */ 500 case TrueTag: 501 case Typ1Tag: 502 case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); 503 case TTCTag: return_trace (u.ttcHeader.sanitize (c)); 504 case DFontTag: return_trace (u.rfHeader.sanitize (c)); 505 default: return_trace (true); 506 } 507 } 508 509 protected: 510 union { 511 Tag tag; /* 4-byte identifier. */ 512 OpenTypeFontFace fontFace; 513 TTCHeader ttcHeader; 514 ResourceForkHeader rfHeader; 515 } u; 516 public: 517 DEFINE_SIZE_UNION (4, tag); 518 }; 519 520 521 } /* namespace OT */ 522 523 524 #endif /* HB_OPEN_FILE_HH */ 525