1 /* 2 * Copyright 2009 Red Hat, Inc. 3 * Copyright 2018 Ebrahim Byagowi 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 */ 27 28 #include "hb.hh" 29 #include "hb-blob.hh" 30 31 #ifdef HAVE_SYS_MMAN_H 32 #ifdef HAVE_UNISTD_H 33 #include <unistd.h> 34 #endif /* HAVE_UNISTD_H */ 35 #include <sys/mman.h> 36 #endif /* HAVE_SYS_MMAN_H */ 37 38 #include <stdio.h> 39 #include <errno.h> 40 #include <stdlib.h> 41 42 43 /** 44 * SECTION: hb-blob 45 * @title: hb-blob 46 * @short_description: Binary data containers 47 * @include: hb.h 48 * 49 * Blobs wrap a chunk of binary data to handle lifecycle management of data 50 * while it is passed between client and HarfBuzz. Blobs are primarily used 51 * to create font faces, but also to access font face tables, as well as 52 * pass around other binary data. 53 **/ 54 55 56 /** 57 * hb_blob_create: (skip) 58 * @data: Pointer to blob data. 59 * @length: Length of @data in bytes. 60 * @mode: Memory mode for @data. 61 * @user_data: Data parameter to pass to @destroy. 62 * @destroy: Callback to call when @data is not needed anymore. 63 * 64 * Creates a new "blob" object wrapping @data. The @mode parameter is used 65 * to negotiate ownership and lifecycle of @data. 66 * 67 * Return value: New blob, or the empty blob if something failed or if @length is 68 * zero. Destroy with hb_blob_destroy(). 69 * 70 * Since: 0.9.2 71 **/ 72 hb_blob_t * 73 hb_blob_create (const char *data, 74 unsigned int length, 75 hb_memory_mode_t mode, 76 void *user_data, 77 hb_destroy_func_t destroy) 78 { 79 hb_blob_t *blob; 80 81 if (!length || 82 length >= 1u << 31 || 83 !(blob = hb_object_create<hb_blob_t> ())) { 84 if (destroy) 85 destroy (user_data); 86 return hb_blob_get_empty (); 87 } 88 89 blob->data = data; 90 blob->length = length; 91 blob->mode = mode; 92 93 blob->user_data = user_data; 94 blob->destroy = destroy; 95 96 if (blob->mode == HB_MEMORY_MODE_DUPLICATE) { 97 blob->mode = HB_MEMORY_MODE_READONLY; 98 if (!blob->try_make_writable ()) { 99 hb_blob_destroy (blob); 100 return hb_blob_get_empty (); 101 } 102 } 103 104 return blob; 105 } 106 107 static void 108 _hb_blob_destroy (void *data) 109 { 110 hb_blob_destroy ((hb_blob_t *) data); 111 } 112 113 /** 114 * hb_blob_create_sub_blob: 115 * @parent: Parent blob. 116 * @offset: Start offset of sub-blob within @parent, in bytes. 117 * @length: Length of sub-blob. 118 * 119 * Returns a blob that represents a range of bytes in @parent. The new 120 * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it 121 * will never modify data in the parent blob. The parent data is not 122 * expected to be modified, and will result in undefined behavior if it 123 * is. 124 * 125 * Makes @parent immutable. 126 * 127 * Return value: New blob, or the empty blob if something failed or if 128 * @length is zero or @offset is beyond the end of @parent's data. Destroy 129 * with hb_blob_destroy(). 130 * 131 * Since: 0.9.2 132 **/ 133 hb_blob_t * 134 hb_blob_create_sub_blob (hb_blob_t *parent, 135 unsigned int offset, 136 unsigned int length) 137 { 138 hb_blob_t *blob; 139 140 if (!length || !parent || offset >= parent->length) 141 return hb_blob_get_empty (); 142 143 hb_blob_make_immutable (parent); 144 145 blob = hb_blob_create (parent->data + offset, 146 MIN (length, parent->length - offset), 147 HB_MEMORY_MODE_READONLY, 148 hb_blob_reference (parent), 149 _hb_blob_destroy); 150 151 return blob; 152 } 153 154 /** 155 * hb_blob_copy_writable_or_fail: 156 * @blob: A blob. 157 * 158 * Makes a writable copy of @blob. 159 * 160 * Return value: New blob, or nullptr if allocation failed. 161 * 162 * Since: 1.8.0 163 **/ 164 hb_blob_t * 165 hb_blob_copy_writable_or_fail (hb_blob_t *blob) 166 { 167 blob = hb_blob_create (blob->data, 168 blob->length, 169 HB_MEMORY_MODE_DUPLICATE, 170 nullptr, 171 nullptr); 172 173 if (unlikely (blob == hb_blob_get_empty ())) 174 blob = nullptr; 175 176 return blob; 177 } 178 179 /** 180 * hb_blob_get_empty: 181 * 182 * Returns the singleton empty blob. 183 * 184 * See TODO:link object types for more information. 185 * 186 * Return value: (transfer full): the empty blob. 187 * 188 * Since: 0.9.2 189 **/ 190 hb_blob_t * 191 hb_blob_get_empty () 192 { 193 return const_cast<hb_blob_t *> (&Null(hb_blob_t)); 194 } 195 196 /** 197 * hb_blob_reference: (skip) 198 * @blob: a blob. 199 * 200 * Increases the reference count on @blob. 201 * 202 * See TODO:link object types for more information. 203 * 204 * Return value: @blob. 205 * 206 * Since: 0.9.2 207 **/ 208 hb_blob_t * 209 hb_blob_reference (hb_blob_t *blob) 210 { 211 return hb_object_reference (blob); 212 } 213 214 /** 215 * hb_blob_destroy: (skip) 216 * @blob: a blob. 217 * 218 * Decreases the reference count on @blob, and if it reaches zero, destroys 219 * @blob, freeing all memory, possibly calling the destroy-callback the blob 220 * was created for if it has not been called already. 221 * 222 * See TODO:link object types for more information. 223 * 224 * Since: 0.9.2 225 **/ 226 void 227 hb_blob_destroy (hb_blob_t *blob) 228 { 229 if (!hb_object_destroy (blob)) return; 230 231 blob->fini_shallow (); 232 233 free (blob); 234 } 235 236 /** 237 * hb_blob_set_user_data: (skip) 238 * @blob: a blob. 239 * @key: key for data to set. 240 * @data: data to set. 241 * @destroy: callback to call when @data is not needed anymore. 242 * @replace: whether to replace an existing data with the same key. 243 * 244 * Return value: 245 * 246 * Since: 0.9.2 247 **/ 248 hb_bool_t 249 hb_blob_set_user_data (hb_blob_t *blob, 250 hb_user_data_key_t *key, 251 void * data, 252 hb_destroy_func_t destroy, 253 hb_bool_t replace) 254 { 255 return hb_object_set_user_data (blob, key, data, destroy, replace); 256 } 257 258 /** 259 * hb_blob_get_user_data: (skip) 260 * @blob: a blob. 261 * @key: key for data to get. 262 * 263 * 264 * 265 * Return value: (transfer none): 266 * 267 * Since: 0.9.2 268 **/ 269 void * 270 hb_blob_get_user_data (hb_blob_t *blob, 271 hb_user_data_key_t *key) 272 { 273 return hb_object_get_user_data (blob, key); 274 } 275 276 277 /** 278 * hb_blob_make_immutable: 279 * @blob: a blob. 280 * 281 * 282 * 283 * Since: 0.9.2 284 **/ 285 void 286 hb_blob_make_immutable (hb_blob_t *blob) 287 { 288 if (hb_object_is_immutable (blob)) 289 return; 290 291 hb_object_make_immutable (blob); 292 } 293 294 /** 295 * hb_blob_is_immutable: 296 * @blob: a blob. 297 * 298 * 299 * 300 * Return value: TODO 301 * 302 * Since: 0.9.2 303 **/ 304 hb_bool_t 305 hb_blob_is_immutable (hb_blob_t *blob) 306 { 307 return hb_object_is_immutable (blob); 308 } 309 310 311 /** 312 * hb_blob_get_length: 313 * @blob: a blob. 314 * 315 * 316 * 317 * Return value: the length of blob data in bytes. 318 * 319 * Since: 0.9.2 320 **/ 321 unsigned int 322 hb_blob_get_length (hb_blob_t *blob) 323 { 324 return blob->length; 325 } 326 327 /** 328 * hb_blob_get_data: 329 * @blob: a blob. 330 * @length: (out): 331 * 332 * 333 * 334 * Returns: (transfer none) (array length=length): 335 * 336 * Since: 0.9.2 337 **/ 338 const char * 339 hb_blob_get_data (hb_blob_t *blob, unsigned int *length) 340 { 341 if (length) 342 *length = blob->length; 343 344 return blob->data; 345 } 346 347 /** 348 * hb_blob_get_data_writable: 349 * @blob: a blob. 350 * @length: (out): output length of the writable data. 351 * 352 * Tries to make blob data writable (possibly copying it) and 353 * return pointer to data. 354 * 355 * Fails if blob has been made immutable, or if memory allocation 356 * fails. 357 * 358 * Returns: (transfer none) (array length=length): Writable blob data, 359 * or %NULL if failed. 360 * 361 * Since: 0.9.2 362 **/ 363 char * 364 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) 365 { 366 if (!blob->try_make_writable ()) { 367 if (length) 368 *length = 0; 369 370 return nullptr; 371 } 372 373 if (length) 374 *length = blob->length; 375 376 return const_cast<char *> (blob->data); 377 } 378 379 380 bool 381 hb_blob_t::try_make_writable_inplace_unix () 382 { 383 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) 384 uintptr_t pagesize = -1, mask, length; 385 const char *addr; 386 387 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) 388 pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE); 389 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) 390 pagesize = (uintptr_t) sysconf (_SC_PAGESIZE); 391 #elif defined(HAVE_GETPAGESIZE) 392 pagesize = (uintptr_t) getpagesize (); 393 #endif 394 395 if ((uintptr_t) -1L == pagesize) { 396 DEBUG_MSG_FUNC (BLOB, this, "failed to get pagesize: %s", strerror (errno)); 397 return false; 398 } 399 DEBUG_MSG_FUNC (BLOB, this, "pagesize is %lu", (unsigned long) pagesize); 400 401 mask = ~(pagesize-1); 402 addr = (const char *) (((uintptr_t) this->data) & mask); 403 length = (const char *) (((uintptr_t) this->data + this->length + pagesize-1) & mask) - addr; 404 DEBUG_MSG_FUNC (BLOB, this, 405 "calling mprotect on [%p..%p] (%lu bytes)", 406 addr, addr+length, (unsigned long) length); 407 if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) { 408 DEBUG_MSG_FUNC (BLOB, this, "mprotect failed: %s", strerror (errno)); 409 return false; 410 } 411 412 this->mode = HB_MEMORY_MODE_WRITABLE; 413 414 DEBUG_MSG_FUNC (BLOB, this, 415 "successfully made [%p..%p] (%lu bytes) writable\n", 416 addr, addr+length, (unsigned long) length); 417 return true; 418 #else 419 return false; 420 #endif 421 } 422 423 bool 424 hb_blob_t::try_make_writable_inplace () 425 { 426 DEBUG_MSG_FUNC (BLOB, this, "making writable inplace\n"); 427 428 if (this->try_make_writable_inplace_unix ()) 429 return true; 430 431 DEBUG_MSG_FUNC (BLOB, this, "making writable -> FAILED\n"); 432 433 /* Failed to make writable inplace, mark that */ 434 this->mode = HB_MEMORY_MODE_READONLY; 435 return false; 436 } 437 438 bool 439 hb_blob_t::try_make_writable () 440 { 441 if (hb_object_is_immutable (this)) 442 return false; 443 444 if (this->mode == HB_MEMORY_MODE_WRITABLE) 445 return true; 446 447 if (this->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && this->try_make_writable_inplace ()) 448 return true; 449 450 if (this->mode == HB_MEMORY_MODE_WRITABLE) 451 return true; 452 453 454 DEBUG_MSG_FUNC (BLOB, this, "current data is -> %p\n", this->data); 455 456 char *new_data; 457 458 new_data = (char *) malloc (this->length); 459 if (unlikely (!new_data)) 460 return false; 461 462 DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data); 463 464 memcpy (new_data, this->data, this->length); 465 this->destroy_user_data (); 466 this->mode = HB_MEMORY_MODE_WRITABLE; 467 this->data = new_data; 468 this->user_data = new_data; 469 this->destroy = free; 470 471 return true; 472 } 473 474 /* 475 * Mmap 476 */ 477 478 #ifdef HAVE_MMAP 479 # include <sys/types.h> 480 # include <sys/stat.h> 481 # include <fcntl.h> 482 #endif 483 484 #ifdef _WIN32 485 # include <windows.h> 486 #else 487 # ifndef O_BINARY 488 # define O_BINARY 0 489 # endif 490 #endif 491 492 #ifndef MAP_NORESERVE 493 # define MAP_NORESERVE 0 494 #endif 495 496 struct hb_mapped_file_t 497 { 498 char *contents; 499 unsigned long length; 500 #ifdef _WIN32 501 HANDLE mapping; 502 #endif 503 }; 504 505 #if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP) 506 static void 507 _hb_mapped_file_destroy (void *file_) 508 { 509 hb_mapped_file_t *file = (hb_mapped_file_t *) file_; 510 #ifdef HAVE_MMAP 511 munmap (file->contents, file->length); 512 #elif defined(_WIN32) 513 UnmapViewOfFile (file->contents); 514 CloseHandle (file->mapping); 515 #else 516 assert (0); // If we don't have mmap we shouldn't reach here 517 #endif 518 519 free (file); 520 } 521 #endif 522 523 /** 524 * hb_blob_create_from_file: 525 * @file_name: font filename. 526 * 527 * Returns: A hb_blob_t pointer with the content of the file 528 * 529 * Since: 1.7.7 530 **/ 531 hb_blob_t * 532 hb_blob_create_from_file (const char *file_name) 533 { 534 /* Adopted from glib's gmappedfile.c with Matthias Clasen and 535 Allison Lortie permission but changed a lot to suit our need. */ 536 #if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) 537 hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); 538 if (unlikely (!file)) return hb_blob_get_empty (); 539 540 int fd = open (file_name, O_RDONLY | O_BINARY, 0); 541 if (unlikely (fd == -1)) goto fail_without_close; 542 543 struct stat st; 544 if (unlikely (fstat (fd, &st) == -1)) goto fail; 545 546 file->length = (unsigned long) st.st_size; 547 file->contents = (char *) mmap (nullptr, file->length, PROT_READ, 548 MAP_PRIVATE | MAP_NORESERVE, fd, 0); 549 550 if (unlikely (file->contents == MAP_FAILED)) goto fail; 551 552 close (fd); 553 554 return hb_blob_create (file->contents, file->length, 555 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, 556 (hb_destroy_func_t) _hb_mapped_file_destroy); 557 558 fail: 559 close (fd); 560 fail_without_close: 561 free (file); 562 563 #elif defined(_WIN32) && !defined(HB_NO_MMAP) 564 hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); 565 if (unlikely (!file)) return hb_blob_get_empty (); 566 567 HANDLE fd; 568 unsigned int size = strlen (file_name) + 1; 569 wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size); 570 if (unlikely (wchar_file_name == nullptr)) goto fail_without_close; 571 mbstowcs (wchar_file_name, file_name, size); 572 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) 573 { 574 CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; 575 ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); 576 ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF; 577 ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000; 578 ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000; 579 ceparams.lpSecurityAttributes = nullptr; 580 ceparams.hTemplateFile = nullptr; 581 fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, 582 OPEN_EXISTING, &ceparams); 583 } 584 #else 585 fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, 586 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 587 nullptr); 588 #endif 589 free (wchar_file_name); 590 591 if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; 592 593 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) 594 { 595 LARGE_INTEGER length; 596 GetFileSizeEx (fd, &length); 597 file->length = length.LowPart; 598 file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr); 599 } 600 #else 601 file->length = (unsigned long) GetFileSize (fd, nullptr); 602 file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); 603 #endif 604 if (unlikely (file->mapping == nullptr)) goto fail; 605 606 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) 607 file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); 608 #else 609 file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); 610 #endif 611 if (unlikely (file->contents == nullptr)) goto fail; 612 613 CloseHandle (fd); 614 return hb_blob_create (file->contents, file->length, 615 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, 616 (hb_destroy_func_t) _hb_mapped_file_destroy); 617 618 fail: 619 CloseHandle (fd); 620 fail_without_close: 621 free (file); 622 623 #endif 624 625 /* The following tries to read a file without knowing its size beforehand 626 It's used as a fallback for systems without mmap or to read from pipes */ 627 unsigned long len = 0, allocated = BUFSIZ * 16; 628 char *data = (char *) malloc (allocated); 629 if (unlikely (data == nullptr)) return hb_blob_get_empty (); 630 631 FILE *fp = fopen (file_name, "rb"); 632 if (unlikely (fp == nullptr)) goto fread_fail_without_close; 633 634 while (!feof (fp)) 635 { 636 if (allocated - len < BUFSIZ) 637 { 638 allocated *= 2; 639 /* Don't allocate and go more than ~536MB, our mmap reader still 640 can cover files like that but lets limit our fallback reader */ 641 if (unlikely (allocated > (2 << 28))) goto fread_fail; 642 char *new_data = (char *) realloc (data, allocated); 643 if (unlikely (new_data == nullptr)) goto fread_fail; 644 data = new_data; 645 } 646 647 unsigned long addition = fread (data + len, 1, allocated - len, fp); 648 649 int err = ferror (fp); 650 #ifdef EINTR // armcc doesn't have it 651 if (unlikely (err == EINTR)) continue; 652 #endif 653 if (unlikely (err)) goto fread_fail; 654 655 len += addition; 656 } 657 658 return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data, 659 (hb_destroy_func_t) free); 660 661 fread_fail: 662 fclose (fp); 663 fread_fail_without_close: 664 free (data); 665 return hb_blob_get_empty (); 666 } 667