gfx/harfbuzz/src/hb-blob.cc

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /*
     2  * Copyright © 2009  Red Hat, Inc.
     3  *
     4  *  This is part of HarfBuzz, a text shaping library.
     5  *
     6  * Permission is hereby granted, without written agreement and without
     7  * license or royalty fees, to use, copy, modify, and distribute this
     8  * software and its documentation for any purpose, provided that the
     9  * above copyright notice and the following two paragraphs appear in
    10  * all copies of this software.
    11  *
    12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    16  * DAMAGE.
    17  *
    18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    23  *
    24  * Red Hat Author(s): Behdad Esfahbod
    25  */
    27 /* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
    28 #define _POSIX_C_SOURCE 199309L
    30 #include "hb-private.hh"
    32 #include "hb-object-private.hh"
    34 #ifdef HAVE_SYS_MMAN_H
    35 #ifdef HAVE_UNISTD_H
    36 #include <unistd.h>
    37 #endif /* HAVE_UNISTD_H */
    38 #include <sys/mman.h>
    39 #endif /* HAVE_SYS_MMAN_H */
    41 #include <stdio.h>
    42 #include <errno.h>
    46 #ifndef HB_DEBUG_BLOB
    47 #define HB_DEBUG_BLOB (HB_DEBUG+0)
    48 #endif
    51 struct hb_blob_t {
    52   hb_object_header_t header;
    53   ASSERT_POD ();
    55   bool immutable;
    57   const char *data;
    58   unsigned int length;
    59   hb_memory_mode_t mode;
    61   void *user_data;
    62   hb_destroy_func_t destroy;
    63 };
    66 static bool _try_writable (hb_blob_t *blob);
    68 static void
    69 _hb_blob_destroy_user_data (hb_blob_t *blob)
    70 {
    71   if (blob->destroy) {
    72     blob->destroy (blob->user_data);
    73     blob->user_data = NULL;
    74     blob->destroy = NULL;
    75   }
    76 }
    78 /**
    79  * hb_blob_create: (Xconstructor)
    80  * @data: (array length=length) (closure user_data) (destroy destroy) (scope notified) (transfer none): Pointer to blob data.
    81  * @length: Length of @data in bytes.
    82  * @mode: Memory mode for @data.
    83  * @user_data: Data parameter to pass to @destroy.
    84  * @destroy: Callback to call when @data is not needed anymore.
    85  *
    86  * Creates a new "blob" object wrapping @data.  The @mode parameter is used
    87  * to negotiate ownership and lifecycle of @data.
    88  *
    89  * Return value: New blob, or the empty blob if something failed or if @length is
    90  * zero.  Destroy with hb_blob_destroy().
    91  *
    92  * Since: 1.0
    93  **/
    94 hb_blob_t *
    95 hb_blob_create (const char        *data,
    96 		unsigned int       length,
    97 		hb_memory_mode_t   mode,
    98 		void              *user_data,
    99 		hb_destroy_func_t  destroy)
   100 {
   101   hb_blob_t *blob;
   103   if (!length || !(blob = hb_object_create<hb_blob_t> ())) {
   104     if (destroy)
   105       destroy (user_data);
   106     return hb_blob_get_empty ();
   107   }
   109   blob->data = data;
   110   blob->length = length;
   111   blob->mode = mode;
   113   blob->user_data = user_data;
   114   blob->destroy = destroy;
   116   if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
   117     blob->mode = HB_MEMORY_MODE_READONLY;
   118     if (!_try_writable (blob)) {
   119       hb_blob_destroy (blob);
   120       return hb_blob_get_empty ();
   121     }
   122   }
   124   return blob;
   125 }
   127 /**
   128  * hb_blob_create_sub_blob:
   129  * @parent: Parent blob.
   130  * @offset: Start offset of sub-blob within @parent, in bytes.
   131  * @length: Length of sub-blob.
   132  *
   133  * Returns a blob that represents a range of bytes in @parent.  The new
   134  * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
   135  * will never modify data in the parent blob.  The parent data is not
   136  * expected to be modified, and will result in undefined behavior if it
   137  * is.
   138  *
   139  * Makes @parent immutable.
   140  *
   141  * Return value: New blob, or the empty blob if something failed or if
   142  * @length is zero or @offset is beyond the end of @parent's data.  Destroy
   143  * with hb_blob_destroy().
   144  *
   145  * Since: 1.0
   146  **/
   147 hb_blob_t *
   148 hb_blob_create_sub_blob (hb_blob_t    *parent,
   149 			 unsigned int  offset,
   150 			 unsigned int  length)
   151 {
   152   hb_blob_t *blob;
   154   if (!length || offset >= parent->length)
   155     return hb_blob_get_empty ();
   157   hb_blob_make_immutable (parent);
   159   blob = hb_blob_create (parent->data + offset,
   160 			 MIN (length, parent->length - offset),
   161 			 HB_MEMORY_MODE_READONLY,
   162 			 hb_blob_reference (parent),
   163 			 (hb_destroy_func_t) hb_blob_destroy);
   165   return blob;
   166 }
   168 /**
   169  * hb_blob_get_empty:
   170  *
   171  * Returns the singleton empty blob.
   172  *
   173  * See TODO:link object types for more information.
   174  *
   175  * Return value: (transfer full): the empty blob.
   176  *
   177  * Since: 1.0
   178  **/
   179 hb_blob_t *
   180 hb_blob_get_empty (void)
   181 {
   182   static const hb_blob_t _hb_blob_nil = {
   183     HB_OBJECT_HEADER_STATIC,
   185     true, /* immutable */
   187     NULL, /* data */
   188     0, /* length */
   189     HB_MEMORY_MODE_READONLY, /* mode */
   191     NULL, /* user_data */
   192     NULL  /* destroy */
   193   };
   195   return const_cast<hb_blob_t *> (&_hb_blob_nil);
   196 }
   198 /**
   199  * hb_blob_reference: (skip)
   200  * @blob: a blob.
   201  *
   202  * Increases the reference count on @blob.
   203  *
   204  * See TODO:link object types for more information.
   205  *
   206  * Return value: @blob.
   207  *
   208  * Since: 1.0
   209  **/
   210 hb_blob_t *
   211 hb_blob_reference (hb_blob_t *blob)
   212 {
   213   return hb_object_reference (blob);
   214 }
   216 /**
   217  * hb_blob_destroy: (skip)
   218  * @blob: a blob.
   219  *
   220  * Descreases the reference count on @blob, and if it reaches zero, destroys
   221  * @blob, freeing all memory, possibly calling the destroy-callback the blob
   222  * was created for if it has not been called already.
   223  *
   224  * See TODO:link object types for more information.
   225  *
   226  * Since: 1.0
   227  **/
   228 void
   229 hb_blob_destroy (hb_blob_t *blob)
   230 {
   231   if (!hb_object_destroy (blob)) return;
   233   _hb_blob_destroy_user_data (blob);
   235   free (blob);
   236 }
   238 /**
   239  * hb_blob_set_user_data: (skip)
   240  * @blob: a blob.
   241  * @key: key for data to set.
   242  * @data: data to set.
   243  * @destroy: callback to call when @data is not needed anymore.
   244  * @replace: whether to replace an existing data with the same key.
   245  *
   246  * Return value: 
   247  *
   248  * Since: 1.0
   249  **/
   250 hb_bool_t
   251 hb_blob_set_user_data (hb_blob_t          *blob,
   252 		       hb_user_data_key_t *key,
   253 		       void *              data,
   254 		       hb_destroy_func_t   destroy,
   255 		       hb_bool_t           replace)
   256 {
   257   return hb_object_set_user_data (blob, key, data, destroy, replace);
   258 }
   260 /**
   261  * hb_blob_get_user_data: (skip)
   262  * @blob: a blob.
   263  * @key: key for data to get.
   264  *
   265  * 
   266  *
   267  * Return value: (transfer none): 
   268  *
   269  * Since: 1.0
   270  **/
   271 void *
   272 hb_blob_get_user_data (hb_blob_t          *blob,
   273 		       hb_user_data_key_t *key)
   274 {
   275   return hb_object_get_user_data (blob, key);
   276 }
   279 /**
   280  * hb_blob_make_immutable:
   281  * @blob: a blob.
   282  *
   283  * 
   284  *
   285  * Since: 1.0
   286  **/
   287 void
   288 hb_blob_make_immutable (hb_blob_t *blob)
   289 {
   290   if (hb_object_is_inert (blob))
   291     return;
   293   blob->immutable = true;
   294 }
   296 /**
   297  * hb_blob_is_immutable:
   298  * @blob: a blob.
   299  *
   300  * 
   301  *
   302  * Return value: TODO
   303  *
   304  * Since: 1.0
   305  **/
   306 hb_bool_t
   307 hb_blob_is_immutable (hb_blob_t *blob)
   308 {
   309   return blob->immutable;
   310 }
   313 /**
   314  * hb_blob_get_length:
   315  * @blob: a blob.
   316  *
   317  * 
   318  *
   319  * Return value: the length of blob data in bytes.
   320  *
   321  * Since: 1.0
   322  **/
   323 unsigned int
   324 hb_blob_get_length (hb_blob_t *blob)
   325 {
   326   return blob->length;
   327 }
   329 /**
   330  * hb_blob_get_data:
   331  * @blob: a blob.
   332  * @length: (out):
   333  *
   334  * 
   335  *
   336  * Returns: (transfer none) (array length=length): 
   337  *
   338  * Since: 1.0
   339  **/
   340 const char *
   341 hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
   342 {
   343   if (length)
   344     *length = blob->length;
   346   return blob->data;
   347 }
   349 /**
   350  * hb_blob_get_data_writable:
   351  * @blob: a blob.
   352  * @length: (out): output length of the writable data.
   353  *
   354  * Tries to make blob data writable (possibly copying it) and
   355  * return pointer to data.
   356  *
   357  * Fails if blob has been made immutable, or if memory allocation
   358  * fails.
   359  *
   360  * Returns: (transfer none) (array length=length): Writable blob data,
   361  * or %NULL if failed.
   362  *
   363  * Since: 1.0
   364  **/
   365 char *
   366 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
   367 {
   368   if (!_try_writable (blob)) {
   369     if (length)
   370       *length = 0;
   372     return NULL;
   373   }
   375   if (length)
   376     *length = blob->length;
   378   return const_cast<char *> (blob->data);
   379 }
   382 static hb_bool_t
   383 _try_make_writable_inplace_unix (hb_blob_t *blob)
   384 {
   385 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
   386   uintptr_t pagesize = -1, mask, length;
   387   const char *addr;
   389 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
   390   pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
   391 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
   392   pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
   393 #elif defined(HAVE_GETPAGESIZE)
   394   pagesize = (uintptr_t) getpagesize ();
   395 #endif
   397   if ((uintptr_t) -1L == pagesize) {
   398     DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno));
   399     return false;
   400   }
   401   DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize);
   403   mask = ~(pagesize-1);
   404   addr = (const char *) (((uintptr_t) blob->data) & mask);
   405   length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask)  - addr;
   406   DEBUG_MSG_FUNC (BLOB, blob,
   407 		  "calling mprotect on [%p..%p] (%lu bytes)",
   408 		  addr, addr+length, (unsigned long) length);
   409   if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
   410     DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno));
   411     return false;
   412   }
   414   blob->mode = HB_MEMORY_MODE_WRITABLE;
   416   DEBUG_MSG_FUNC (BLOB, blob,
   417 		  "successfully made [%p..%p] (%lu bytes) writable\n",
   418 		  addr, addr+length, (unsigned long) length);
   419   return true;
   420 #else
   421   return false;
   422 #endif
   423 }
   425 static bool
   426 _try_writable_inplace (hb_blob_t *blob)
   427 {
   428   DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n");
   430   if (_try_make_writable_inplace_unix (blob))
   431     return true;
   433   DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n");
   435   /* Failed to make writable inplace, mark that */
   436   blob->mode = HB_MEMORY_MODE_READONLY;
   437   return false;
   438 }
   440 static bool
   441 _try_writable (hb_blob_t *blob)
   442 {
   443   if (blob->immutable)
   444     return false;
   446   if (blob->mode == HB_MEMORY_MODE_WRITABLE)
   447     return true;
   449   if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob))
   450     return true;
   452   if (blob->mode == HB_MEMORY_MODE_WRITABLE)
   453     return true;
   456   DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data);
   458   char *new_data;
   460   new_data = (char *) malloc (blob->length);
   461   if (unlikely (!new_data))
   462     return false;
   464   DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data);
   466   memcpy (new_data, blob->data, blob->length);
   467   _hb_blob_destroy_user_data (blob);
   468   blob->mode = HB_MEMORY_MODE_WRITABLE;
   469   blob->data = new_data;
   470   blob->user_data = new_data;
   471   blob->destroy = free;
   473   return true;
   474 }

mercurial