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 #endif 493 494 #ifndef _O_BINARY 495 # define _O_BINARY 0 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 free (file->contents); 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 bool writable = false; 540 hb_memory_mode_t mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE; 541 hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); 542 if (unlikely (!file)) return hb_blob_get_empty (); 543 544 #ifdef HAVE_MMAP 545 int fd = open (file_name, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0); 546 # define CLOSE close 547 if (unlikely (fd == -1)) goto fail_without_close; 548 549 struct stat st; 550 if (unlikely (fstat (fd, &st) == -1)) goto fail; 551 552 // See https://github.com/GNOME/glib/blob/f9faac7/glib/gmappedfile.c#L139-L142 553 if (unlikely (st.st_size == 0 && S_ISREG (st.st_mode))) goto fail; 554 555 file->length = (unsigned long) st.st_size; 556 file->contents = (char *) mmap (nullptr, file->length, 557 writable ? PROT_READ|PROT_WRITE : PROT_READ, 558 MAP_PRIVATE | MAP_NORESERVE, fd, 0); 559 560 if (unlikely (file->contents == MAP_FAILED)) goto fail; 561 562 #elif defined(_WIN32) || defined(__CYGWIN__) 563 HANDLE fd = CreateFile (file_name, 564 writable ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ, 565 FILE_SHARE_READ, nullptr, OPEN_EXISTING, 566 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); 567 # define CLOSE CloseHandle 568 569 if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; 570 571 file->length = (unsigned long) GetFileSize (fd, nullptr); 572 file->mapping = CreateFileMapping (fd, nullptr, 573 writable ? PAGE_WRITECOPY : PAGE_READONLY, 574 0, 0, nullptr); 575 if (unlikely (file->mapping == nullptr)) goto fail; 576 577 file->contents = (char *) MapViewOfFile (file->mapping, 578 writable ? FILE_MAP_COPY : FILE_MAP_READ, 579 0, 0, 0); 580 if (unlikely (file->contents == nullptr)) goto fail; 581 582 #else 583 mm = HB_MEMORY_MODE_WRITABLE; 584 585 FILE *fd = fopen (file_name, "rb"); 586 # define CLOSE fclose 587 if (unlikely (!fd)) goto fail_without_close; 588 589 fseek (fd, 0, SEEK_END); 590 file->length = ftell (fd); 591 rewind (fd); 592 file->contents = (char *) malloc (file->length); 593 if (unlikely (!file->contents)) goto fail; 594 595 if (unlikely (fread (file->contents, 1, file->length, fd) != file->length)) 596 goto fail; 597 598 #endif 599 600 CLOSE (fd); 601 return hb_blob_create (file->contents, file->length, mm, (void *) file, 602 (hb_destroy_func_t) _hb_mapped_file_destroy); 603 604 fail: 605 CLOSE (fd); 606 #undef CLOSE 607 fail_without_close: 608 free (file); 609 return hb_blob_get_empty (); 610 } | 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 } |