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