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