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