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 OpenTypeOffsetTable; 52 struct TTCHeader; 53 54 55 typedef struct TableRecord 56 { cmpOT::TableRecord57 int cmp (Tag t) const { return -t.cmp (tag); } 58 cmpOT::TableRecord59 HB_INTERNAL 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 OpenTypeOffsetTable 82 { 83 friend struct OpenTypeFontFile; 84 get_table_countOT::OpenTypeOffsetTable85 unsigned int get_table_count () const { return tables.len; } get_tableOT::OpenTypeOffsetTable86 const TableRecord& get_table (unsigned int i) const 87 { return tables[i]; } get_table_tagsOT::OpenTypeOffsetTable88 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 + tables.sub_array (start_offset, table_count) 95 | hb_map (&TableRecord::tag) 96 | hb_sink (hb_array (table_tags, *table_count)) 97 ; 98 } 99 return tables.len; 100 } find_table_indexOT::OpenTypeOffsetTable101 bool find_table_index (hb_tag_t tag, unsigned int *table_index) const 102 { 103 Tag t; 104 t = tag; 105 return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); 106 } get_table_by_tagOT::OpenTypeOffsetTable107 const TableRecord& get_table_by_tag (hb_tag_t tag) const 108 { 109 unsigned int table_index; 110 find_table_index (tag, &table_index); 111 return get_table (table_index); 112 } 113 114 public: 115 116 template <typename item_t> serializeOT::OpenTypeOffsetTable117 bool serialize (hb_serialize_context_t *c, 118 hb_tag_t sfnt_tag, 119 hb_array_t<item_t> items) 120 { 121 TRACE_SERIALIZE (this); 122 /* Alloc 12 for the OTHeader. */ 123 if (unlikely (!c->extend_min (*this))) return_trace (false); 124 /* Write sfntVersion (bytes 0..3). */ 125 sfnt_version = sfnt_tag; 126 /* Take space for numTables, searchRange, entrySelector, RangeShift 127 * and the TableRecords themselves. */ 128 if (unlikely (!tables.serialize (c, items.length))) return_trace (false); 129 130 const char *dir_end = (const char *) c->head; 131 HBUINT32 *checksum_adjustment = nullptr; 132 133 /* Write OffsetTables, alloc for and write actual table blobs. */ 134 for (unsigned int i = 0; i < tables.len; i++) 135 { 136 TableRecord &rec = tables.arrayZ[i]; 137 hb_blob_t *blob = items[i].blob; 138 rec.tag = items[i].tag; 139 rec.length = blob->length; 140 rec.offset.serialize (c, this); 141 142 /* Allocate room for the table and copy it. */ 143 char *start = (char *) c->allocate_size<void> (rec.length); 144 if (unlikely (!start)) return false; 145 146 if (likely (rec.length)) 147 memcpy (start, blob->data, rec.length); 148 149 /* 4-byte alignment. */ 150 c->align (4); 151 const char *end = (const char *) c->head; 152 153 if (items[i].tag == HB_OT_TAG_head && 154 (unsigned) (end - start) >= head::static_size) 155 { 156 head *h = (head *) start; 157 checksum_adjustment = &h->checkSumAdjustment; 158 *checksum_adjustment = 0; 159 } 160 161 rec.checkSum.set_for_data (start, end - start); 162 } 163 164 tables.qsort (); 165 166 if (checksum_adjustment) 167 { 168 CheckSum checksum; 169 170 /* The following line is a slower version of the following block. */ 171 //checksum.set_for_data (this, (const char *) c->head - (const char *) this); 172 checksum.set_for_data (this, dir_end - (const char *) this); 173 for (unsigned int i = 0; i < items.length; i++) 174 { 175 TableRecord &rec = tables.arrayZ[i]; 176 checksum = checksum + rec.checkSum; 177 } 178 179 *checksum_adjustment = 0xB1B0AFBAu - checksum; 180 } 181 182 return_trace (true); 183 } 184 sanitizeOT::OpenTypeOffsetTable185 bool sanitize (hb_sanitize_context_t *c) const 186 { 187 TRACE_SANITIZE (this); 188 return_trace (c->check_struct (this) && tables.sanitize (c)); 189 } 190 191 protected: 192 Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */ 193 BinSearchArrayOf<TableRecord> 194 tables; 195 public: 196 DEFINE_SIZE_ARRAY (12, tables); 197 } OpenTypeFontFace; 198 199 200 /* 201 * TrueType Collections 202 */ 203 204 struct TTCHeaderVersion1 205 { 206 friend struct TTCHeader; 207 get_face_countOT::TTCHeaderVersion1208 unsigned int get_face_count () const { return table.len; } get_faceOT::TTCHeaderVersion1209 const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } 210 sanitizeOT::TTCHeaderVersion1211 bool sanitize (hb_sanitize_context_t *c) const 212 { 213 TRACE_SANITIZE (this); 214 return_trace (table.sanitize (c, this)); 215 } 216 217 protected: 218 Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ 219 FixedVersion<>version; /* Version of the TTC Header (1.0), 220 * 0x00010000u */ 221 Array32Of<Offset32To<OpenTypeOffsetTable>> 222 table; /* Array of offsets to the OffsetTable for each font 223 * from the beginning of the file */ 224 public: 225 DEFINE_SIZE_ARRAY (12, table); 226 }; 227 228 struct TTCHeader 229 { 230 friend struct OpenTypeFontFile; 231 232 private: 233 get_face_countOT::TTCHeader234 unsigned int get_face_count () const 235 { 236 switch (u.header.version.major) { 237 case 2: /* version 2 is compatible with version 1 */ 238 case 1: return u.version1.get_face_count (); 239 default:return 0; 240 } 241 } get_faceOT::TTCHeader242 const OpenTypeFontFace& get_face (unsigned int i) const 243 { 244 switch (u.header.version.major) { 245 case 2: /* version 2 is compatible with version 1 */ 246 case 1: return u.version1.get_face (i); 247 default:return Null (OpenTypeFontFace); 248 } 249 } 250 sanitizeOT::TTCHeader251 bool sanitize (hb_sanitize_context_t *c) const 252 { 253 TRACE_SANITIZE (this); 254 if (unlikely (!u.header.version.sanitize (c))) return_trace (false); 255 switch (u.header.version.major) { 256 case 2: /* version 2 is compatible with version 1 */ 257 case 1: return_trace (u.version1.sanitize (c)); 258 default:return_trace (true); 259 } 260 } 261 262 protected: 263 union { 264 struct { 265 Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ 266 FixedVersion<>version; /* Version of the TTC Header (1.0 or 2.0), 267 * 0x00010000u or 0x00020000u */ 268 } header; 269 TTCHeaderVersion1 version1; 270 } u; 271 }; 272 273 /* 274 * Mac Resource Fork 275 * 276 * http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html 277 */ 278 279 struct ResourceRecord 280 { get_faceOT::ResourceRecord281 const OpenTypeFontFace & get_face (const void *data_base) const 282 { return * reinterpret_cast<const OpenTypeFontFace *> ((data_base+offset).arrayZ); } 283 sanitizeOT::ResourceRecord284 bool sanitize (hb_sanitize_context_t *c, 285 const void *data_base) const 286 { 287 TRACE_SANITIZE (this); 288 return_trace (c->check_struct (this) && 289 offset.sanitize (c, data_base) && 290 get_face (data_base).sanitize (c)); 291 } 292 293 protected: 294 HBUINT16 id; /* Resource ID. */ 295 HBINT16 nameOffset; /* Offset from beginning of resource name list 296 * to resource name, -1 means there is none. */ 297 HBUINT8 attrs; /* Resource attributes */ 298 NNOffset24To<Array32Of<HBUINT8>> 299 offset; /* Offset from beginning of data block to 300 * data for this resource */ 301 HBUINT32 reserved; /* Reserved for handle to resource */ 302 public: 303 DEFINE_SIZE_STATIC (12); 304 }; 305 306 #define HB_TAG_sfnt HB_TAG ('s','f','n','t') 307 308 struct ResourceTypeRecord 309 { get_resource_countOT::ResourceTypeRecord310 unsigned int get_resource_count () const 311 { return tag == HB_TAG_sfnt ? resCountM1 + 1 : 0; } 312 is_sfntOT::ResourceTypeRecord313 bool is_sfnt () const { return tag == HB_TAG_sfnt; } 314 get_resource_recordOT::ResourceTypeRecord315 const ResourceRecord& get_resource_record (unsigned int i, 316 const void *type_base) const 317 { return (type_base+resourcesZ).as_array (get_resource_count ())[i]; } 318 sanitizeOT::ResourceTypeRecord319 bool sanitize (hb_sanitize_context_t *c, 320 const void *type_base, 321 const void *data_base) const 322 { 323 TRACE_SANITIZE (this); 324 return_trace (c->check_struct (this) && 325 resourcesZ.sanitize (c, type_base, 326 get_resource_count (), 327 data_base)); 328 } 329 330 protected: 331 Tag tag; /* Resource type. */ 332 HBUINT16 resCountM1; /* Number of resources minus 1. */ 333 NNOffset16To<UnsizedArrayOf<ResourceRecord>> 334 resourcesZ; /* Offset from beginning of resource type list 335 * to reference item list for this type. */ 336 public: 337 DEFINE_SIZE_STATIC (8); 338 }; 339 340 struct ResourceMap 341 { get_face_countOT::ResourceMap342 unsigned int get_face_count () const 343 { 344 unsigned int count = get_type_count (); 345 for (unsigned int i = 0; i < count; i++) 346 { 347 const ResourceTypeRecord& type = get_type_record (i); 348 if (type.is_sfnt ()) 349 return type.get_resource_count (); 350 } 351 return 0; 352 } 353 get_faceOT::ResourceMap354 const OpenTypeFontFace& get_face (unsigned int idx, 355 const void *data_base) const 356 { 357 unsigned int count = get_type_count (); 358 for (unsigned int i = 0; i < count; i++) 359 { 360 const ResourceTypeRecord& type = get_type_record (i); 361 /* The check for idx < count is here because ResourceRecord is NOT null-safe. 362 * Because an offset of 0 there does NOT mean null. */ 363 if (type.is_sfnt () && idx < type.get_resource_count ()) 364 return type.get_resource_record (idx, &(this+typeList)).get_face (data_base); 365 } 366 return Null (OpenTypeFontFace); 367 } 368 sanitizeOT::ResourceMap369 bool sanitize (hb_sanitize_context_t *c, const void *data_base) const 370 { 371 TRACE_SANITIZE (this); 372 return_trace (c->check_struct (this) && 373 typeList.sanitize (c, this, 374 &(this+typeList), 375 data_base)); 376 } 377 378 private: get_type_countOT::ResourceMap379 unsigned int get_type_count () const { return (this+typeList).lenM1 + 1; } 380 get_type_recordOT::ResourceMap381 const ResourceTypeRecord& get_type_record (unsigned int i) const 382 { return (this+typeList)[i]; } 383 384 protected: 385 HBUINT8 reserved0[16]; /* Reserved for copy of resource header */ 386 HBUINT32 reserved1; /* Reserved for handle to next resource map */ 387 HBUINT16 resreved2; /* Reserved for file reference number */ 388 HBUINT16 attrs; /* Resource fork attribute */ 389 NNOffset16To<ArrayOfM1<ResourceTypeRecord>> 390 typeList; /* Offset from beginning of map to 391 * resource type list */ 392 Offset16 nameList; /* Offset from beginning of map to 393 * resource name list */ 394 public: 395 DEFINE_SIZE_STATIC (28); 396 }; 397 398 struct ResourceForkHeader 399 { get_face_countOT::ResourceForkHeader400 unsigned int get_face_count () const 401 { return (this+map).get_face_count (); } 402 get_faceOT::ResourceForkHeader403 const OpenTypeFontFace& get_face (unsigned int idx, 404 unsigned int *base_offset = nullptr) const 405 { 406 const OpenTypeFontFace &face = (this+map).get_face (idx, &(this+data)); 407 if (base_offset) 408 *base_offset = (const char *) &face - (const char *) this; 409 return face; 410 } 411 sanitizeOT::ResourceForkHeader412 bool sanitize (hb_sanitize_context_t *c) const 413 { 414 TRACE_SANITIZE (this); 415 return_trace (c->check_struct (this) && 416 data.sanitize (c, this, dataLen) && 417 map.sanitize (c, this, &(this+data))); 418 } 419 420 protected: 421 NNOffset32To<UnsizedArrayOf<HBUINT8>> 422 data; /* Offset from beginning of resource fork 423 * to resource data */ 424 NNOffset32To<ResourceMap > 425 map; /* Offset from beginning of resource fork 426 * to resource map */ 427 HBUINT32 dataLen; /* Length of resource data */ 428 HBUINT32 mapLen; /* Length of resource map */ 429 public: 430 DEFINE_SIZE_STATIC (16); 431 }; 432 433 /* 434 * OpenType Font File 435 */ 436 437 struct OpenTypeFontFile 438 { 439 enum { 440 CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */ 441 TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */ 442 TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */ 443 DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */ 444 TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */ 445 Typ1Tag = HB_TAG ('t','y','p','1') /* Obsolete Apple Type1 font in SFNT container */ 446 }; 447 get_tagOT::OpenTypeFontFile448 hb_tag_t get_tag () const { return u.tag; } 449 get_face_countOT::OpenTypeFontFile450 unsigned int get_face_count () const 451 { 452 switch (u.tag) { 453 case CFFTag: /* All the non-collection tags */ 454 case TrueTag: 455 case Typ1Tag: 456 case TrueTypeTag: return 1; 457 case TTCTag: return u.ttcHeader.get_face_count (); 458 case DFontTag: return u.rfHeader.get_face_count (); 459 default: return 0; 460 } 461 } get_faceOT::OpenTypeFontFile462 const OpenTypeFontFace& get_face (unsigned int i, unsigned int *base_offset = nullptr) const 463 { 464 if (base_offset) 465 *base_offset = 0; 466 switch (u.tag) { 467 /* Note: for non-collection SFNT data we ignore index. This is because 468 * Apple dfont container is a container of SFNT's. So each SFNT is a 469 * non-TTC, but the index is more than zero. */ 470 case CFFTag: /* All the non-collection tags */ 471 case TrueTag: 472 case Typ1Tag: 473 case TrueTypeTag: return u.fontFace; 474 case TTCTag: return u.ttcHeader.get_face (i); 475 case DFontTag: return u.rfHeader.get_face (i, base_offset); 476 default: return Null (OpenTypeFontFace); 477 } 478 } 479 480 template <typename item_t> serialize_singleOT::OpenTypeFontFile481 bool serialize_single (hb_serialize_context_t *c, 482 hb_tag_t sfnt_tag, 483 hb_array_t<item_t> items) 484 { 485 TRACE_SERIALIZE (this); 486 assert (sfnt_tag != TTCTag); 487 if (unlikely (!c->extend_min (*this))) return_trace (false); 488 return_trace (u.fontFace.serialize (c, sfnt_tag, items)); 489 } 490 sanitizeOT::OpenTypeFontFile491 bool sanitize (hb_sanitize_context_t *c) const 492 { 493 TRACE_SANITIZE (this); 494 if (unlikely (!u.tag.sanitize (c))) return_trace (false); 495 switch (u.tag) { 496 case CFFTag: /* All the non-collection tags */ 497 case TrueTag: 498 case Typ1Tag: 499 case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); 500 case TTCTag: return_trace (u.ttcHeader.sanitize (c)); 501 case DFontTag: return_trace (u.rfHeader.sanitize (c)); 502 default: return_trace (true); 503 } 504 } 505 506 protected: 507 union { 508 Tag tag; /* 4-byte identifier. */ 509 OpenTypeFontFace fontFace; 510 TTCHeader ttcHeader; 511 ResourceForkHeader rfHeader; 512 } u; 513 public: 514 DEFINE_SIZE_UNION (4, tag); 515 }; 516 517 518 } /* namespace OT */ 519 520 521 #endif /* HB_OPEN_FILE_HH */ 522