1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-blob.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,474 @@ 1.4 +/* 1.5 + * Copyright © 2009 Red Hat, Inc. 1.6 + * 1.7 + * This is part of HarfBuzz, a text shaping library. 1.8 + * 1.9 + * Permission is hereby granted, without written agreement and without 1.10 + * license or royalty fees, to use, copy, modify, and distribute this 1.11 + * software and its documentation for any purpose, provided that the 1.12 + * above copyright notice and the following two paragraphs appear in 1.13 + * all copies of this software. 1.14 + * 1.15 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.16 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.17 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.18 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.19 + * DAMAGE. 1.20 + * 1.21 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.22 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.23 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.24 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.25 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.26 + * 1.27 + * Red Hat Author(s): Behdad Esfahbod 1.28 + */ 1.29 + 1.30 +/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */ 1.31 +#define _POSIX_C_SOURCE 199309L 1.32 + 1.33 +#include "hb-private.hh" 1.34 + 1.35 +#include "hb-object-private.hh" 1.36 + 1.37 +#ifdef HAVE_SYS_MMAN_H 1.38 +#ifdef HAVE_UNISTD_H 1.39 +#include <unistd.h> 1.40 +#endif /* HAVE_UNISTD_H */ 1.41 +#include <sys/mman.h> 1.42 +#endif /* HAVE_SYS_MMAN_H */ 1.43 + 1.44 +#include <stdio.h> 1.45 +#include <errno.h> 1.46 + 1.47 + 1.48 + 1.49 +#ifndef HB_DEBUG_BLOB 1.50 +#define HB_DEBUG_BLOB (HB_DEBUG+0) 1.51 +#endif 1.52 + 1.53 + 1.54 +struct hb_blob_t { 1.55 + hb_object_header_t header; 1.56 + ASSERT_POD (); 1.57 + 1.58 + bool immutable; 1.59 + 1.60 + const char *data; 1.61 + unsigned int length; 1.62 + hb_memory_mode_t mode; 1.63 + 1.64 + void *user_data; 1.65 + hb_destroy_func_t destroy; 1.66 +}; 1.67 + 1.68 + 1.69 +static bool _try_writable (hb_blob_t *blob); 1.70 + 1.71 +static void 1.72 +_hb_blob_destroy_user_data (hb_blob_t *blob) 1.73 +{ 1.74 + if (blob->destroy) { 1.75 + blob->destroy (blob->user_data); 1.76 + blob->user_data = NULL; 1.77 + blob->destroy = NULL; 1.78 + } 1.79 +} 1.80 + 1.81 +/** 1.82 + * hb_blob_create: (Xconstructor) 1.83 + * @data: (array length=length) (closure user_data) (destroy destroy) (scope notified) (transfer none): Pointer to blob data. 1.84 + * @length: Length of @data in bytes. 1.85 + * @mode: Memory mode for @data. 1.86 + * @user_data: Data parameter to pass to @destroy. 1.87 + * @destroy: Callback to call when @data is not needed anymore. 1.88 + * 1.89 + * Creates a new "blob" object wrapping @data. The @mode parameter is used 1.90 + * to negotiate ownership and lifecycle of @data. 1.91 + * 1.92 + * Return value: New blob, or the empty blob if something failed or if @length is 1.93 + * zero. Destroy with hb_blob_destroy(). 1.94 + * 1.95 + * Since: 1.0 1.96 + **/ 1.97 +hb_blob_t * 1.98 +hb_blob_create (const char *data, 1.99 + unsigned int length, 1.100 + hb_memory_mode_t mode, 1.101 + void *user_data, 1.102 + hb_destroy_func_t destroy) 1.103 +{ 1.104 + hb_blob_t *blob; 1.105 + 1.106 + if (!length || !(blob = hb_object_create<hb_blob_t> ())) { 1.107 + if (destroy) 1.108 + destroy (user_data); 1.109 + return hb_blob_get_empty (); 1.110 + } 1.111 + 1.112 + blob->data = data; 1.113 + blob->length = length; 1.114 + blob->mode = mode; 1.115 + 1.116 + blob->user_data = user_data; 1.117 + blob->destroy = destroy; 1.118 + 1.119 + if (blob->mode == HB_MEMORY_MODE_DUPLICATE) { 1.120 + blob->mode = HB_MEMORY_MODE_READONLY; 1.121 + if (!_try_writable (blob)) { 1.122 + hb_blob_destroy (blob); 1.123 + return hb_blob_get_empty (); 1.124 + } 1.125 + } 1.126 + 1.127 + return blob; 1.128 +} 1.129 + 1.130 +/** 1.131 + * hb_blob_create_sub_blob: 1.132 + * @parent: Parent blob. 1.133 + * @offset: Start offset of sub-blob within @parent, in bytes. 1.134 + * @length: Length of sub-blob. 1.135 + * 1.136 + * Returns a blob that represents a range of bytes in @parent. The new 1.137 + * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it 1.138 + * will never modify data in the parent blob. The parent data is not 1.139 + * expected to be modified, and will result in undefined behavior if it 1.140 + * is. 1.141 + * 1.142 + * Makes @parent immutable. 1.143 + * 1.144 + * Return value: New blob, or the empty blob if something failed or if 1.145 + * @length is zero or @offset is beyond the end of @parent's data. Destroy 1.146 + * with hb_blob_destroy(). 1.147 + * 1.148 + * Since: 1.0 1.149 + **/ 1.150 +hb_blob_t * 1.151 +hb_blob_create_sub_blob (hb_blob_t *parent, 1.152 + unsigned int offset, 1.153 + unsigned int length) 1.154 +{ 1.155 + hb_blob_t *blob; 1.156 + 1.157 + if (!length || offset >= parent->length) 1.158 + return hb_blob_get_empty (); 1.159 + 1.160 + hb_blob_make_immutable (parent); 1.161 + 1.162 + blob = hb_blob_create (parent->data + offset, 1.163 + MIN (length, parent->length - offset), 1.164 + HB_MEMORY_MODE_READONLY, 1.165 + hb_blob_reference (parent), 1.166 + (hb_destroy_func_t) hb_blob_destroy); 1.167 + 1.168 + return blob; 1.169 +} 1.170 + 1.171 +/** 1.172 + * hb_blob_get_empty: 1.173 + * 1.174 + * Returns the singleton empty blob. 1.175 + * 1.176 + * See TODO:link object types for more information. 1.177 + * 1.178 + * Return value: (transfer full): the empty blob. 1.179 + * 1.180 + * Since: 1.0 1.181 + **/ 1.182 +hb_blob_t * 1.183 +hb_blob_get_empty (void) 1.184 +{ 1.185 + static const hb_blob_t _hb_blob_nil = { 1.186 + HB_OBJECT_HEADER_STATIC, 1.187 + 1.188 + true, /* immutable */ 1.189 + 1.190 + NULL, /* data */ 1.191 + 0, /* length */ 1.192 + HB_MEMORY_MODE_READONLY, /* mode */ 1.193 + 1.194 + NULL, /* user_data */ 1.195 + NULL /* destroy */ 1.196 + }; 1.197 + 1.198 + return const_cast<hb_blob_t *> (&_hb_blob_nil); 1.199 +} 1.200 + 1.201 +/** 1.202 + * hb_blob_reference: (skip) 1.203 + * @blob: a blob. 1.204 + * 1.205 + * Increases the reference count on @blob. 1.206 + * 1.207 + * See TODO:link object types for more information. 1.208 + * 1.209 + * Return value: @blob. 1.210 + * 1.211 + * Since: 1.0 1.212 + **/ 1.213 +hb_blob_t * 1.214 +hb_blob_reference (hb_blob_t *blob) 1.215 +{ 1.216 + return hb_object_reference (blob); 1.217 +} 1.218 + 1.219 +/** 1.220 + * hb_blob_destroy: (skip) 1.221 + * @blob: a blob. 1.222 + * 1.223 + * Descreases the reference count on @blob, and if it reaches zero, destroys 1.224 + * @blob, freeing all memory, possibly calling the destroy-callback the blob 1.225 + * was created for if it has not been called already. 1.226 + * 1.227 + * See TODO:link object types for more information. 1.228 + * 1.229 + * Since: 1.0 1.230 + **/ 1.231 +void 1.232 +hb_blob_destroy (hb_blob_t *blob) 1.233 +{ 1.234 + if (!hb_object_destroy (blob)) return; 1.235 + 1.236 + _hb_blob_destroy_user_data (blob); 1.237 + 1.238 + free (blob); 1.239 +} 1.240 + 1.241 +/** 1.242 + * hb_blob_set_user_data: (skip) 1.243 + * @blob: a blob. 1.244 + * @key: key for data to set. 1.245 + * @data: data to set. 1.246 + * @destroy: callback to call when @data is not needed anymore. 1.247 + * @replace: whether to replace an existing data with the same key. 1.248 + * 1.249 + * Return value: 1.250 + * 1.251 + * Since: 1.0 1.252 + **/ 1.253 +hb_bool_t 1.254 +hb_blob_set_user_data (hb_blob_t *blob, 1.255 + hb_user_data_key_t *key, 1.256 + void * data, 1.257 + hb_destroy_func_t destroy, 1.258 + hb_bool_t replace) 1.259 +{ 1.260 + return hb_object_set_user_data (blob, key, data, destroy, replace); 1.261 +} 1.262 + 1.263 +/** 1.264 + * hb_blob_get_user_data: (skip) 1.265 + * @blob: a blob. 1.266 + * @key: key for data to get. 1.267 + * 1.268 + * 1.269 + * 1.270 + * Return value: (transfer none): 1.271 + * 1.272 + * Since: 1.0 1.273 + **/ 1.274 +void * 1.275 +hb_blob_get_user_data (hb_blob_t *blob, 1.276 + hb_user_data_key_t *key) 1.277 +{ 1.278 + return hb_object_get_user_data (blob, key); 1.279 +} 1.280 + 1.281 + 1.282 +/** 1.283 + * hb_blob_make_immutable: 1.284 + * @blob: a blob. 1.285 + * 1.286 + * 1.287 + * 1.288 + * Since: 1.0 1.289 + **/ 1.290 +void 1.291 +hb_blob_make_immutable (hb_blob_t *blob) 1.292 +{ 1.293 + if (hb_object_is_inert (blob)) 1.294 + return; 1.295 + 1.296 + blob->immutable = true; 1.297 +} 1.298 + 1.299 +/** 1.300 + * hb_blob_is_immutable: 1.301 + * @blob: a blob. 1.302 + * 1.303 + * 1.304 + * 1.305 + * Return value: TODO 1.306 + * 1.307 + * Since: 1.0 1.308 + **/ 1.309 +hb_bool_t 1.310 +hb_blob_is_immutable (hb_blob_t *blob) 1.311 +{ 1.312 + return blob->immutable; 1.313 +} 1.314 + 1.315 + 1.316 +/** 1.317 + * hb_blob_get_length: 1.318 + * @blob: a blob. 1.319 + * 1.320 + * 1.321 + * 1.322 + * Return value: the length of blob data in bytes. 1.323 + * 1.324 + * Since: 1.0 1.325 + **/ 1.326 +unsigned int 1.327 +hb_blob_get_length (hb_blob_t *blob) 1.328 +{ 1.329 + return blob->length; 1.330 +} 1.331 + 1.332 +/** 1.333 + * hb_blob_get_data: 1.334 + * @blob: a blob. 1.335 + * @length: (out): 1.336 + * 1.337 + * 1.338 + * 1.339 + * Returns: (transfer none) (array length=length): 1.340 + * 1.341 + * Since: 1.0 1.342 + **/ 1.343 +const char * 1.344 +hb_blob_get_data (hb_blob_t *blob, unsigned int *length) 1.345 +{ 1.346 + if (length) 1.347 + *length = blob->length; 1.348 + 1.349 + return blob->data; 1.350 +} 1.351 + 1.352 +/** 1.353 + * hb_blob_get_data_writable: 1.354 + * @blob: a blob. 1.355 + * @length: (out): output length of the writable data. 1.356 + * 1.357 + * Tries to make blob data writable (possibly copying it) and 1.358 + * return pointer to data. 1.359 + * 1.360 + * Fails if blob has been made immutable, or if memory allocation 1.361 + * fails. 1.362 + * 1.363 + * Returns: (transfer none) (array length=length): Writable blob data, 1.364 + * or %NULL if failed. 1.365 + * 1.366 + * Since: 1.0 1.367 + **/ 1.368 +char * 1.369 +hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) 1.370 +{ 1.371 + if (!_try_writable (blob)) { 1.372 + if (length) 1.373 + *length = 0; 1.374 + 1.375 + return NULL; 1.376 + } 1.377 + 1.378 + if (length) 1.379 + *length = blob->length; 1.380 + 1.381 + return const_cast<char *> (blob->data); 1.382 +} 1.383 + 1.384 + 1.385 +static hb_bool_t 1.386 +_try_make_writable_inplace_unix (hb_blob_t *blob) 1.387 +{ 1.388 +#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) 1.389 + uintptr_t pagesize = -1, mask, length; 1.390 + const char *addr; 1.391 + 1.392 +#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) 1.393 + pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE); 1.394 +#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) 1.395 + pagesize = (uintptr_t) sysconf (_SC_PAGESIZE); 1.396 +#elif defined(HAVE_GETPAGESIZE) 1.397 + pagesize = (uintptr_t) getpagesize (); 1.398 +#endif 1.399 + 1.400 + if ((uintptr_t) -1L == pagesize) { 1.401 + DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno)); 1.402 + return false; 1.403 + } 1.404 + DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize); 1.405 + 1.406 + mask = ~(pagesize-1); 1.407 + addr = (const char *) (((uintptr_t) blob->data) & mask); 1.408 + length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask) - addr; 1.409 + DEBUG_MSG_FUNC (BLOB, blob, 1.410 + "calling mprotect on [%p..%p] (%lu bytes)", 1.411 + addr, addr+length, (unsigned long) length); 1.412 + if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) { 1.413 + DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno)); 1.414 + return false; 1.415 + } 1.416 + 1.417 + blob->mode = HB_MEMORY_MODE_WRITABLE; 1.418 + 1.419 + DEBUG_MSG_FUNC (BLOB, blob, 1.420 + "successfully made [%p..%p] (%lu bytes) writable\n", 1.421 + addr, addr+length, (unsigned long) length); 1.422 + return true; 1.423 +#else 1.424 + return false; 1.425 +#endif 1.426 +} 1.427 + 1.428 +static bool 1.429 +_try_writable_inplace (hb_blob_t *blob) 1.430 +{ 1.431 + DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n"); 1.432 + 1.433 + if (_try_make_writable_inplace_unix (blob)) 1.434 + return true; 1.435 + 1.436 + DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n"); 1.437 + 1.438 + /* Failed to make writable inplace, mark that */ 1.439 + blob->mode = HB_MEMORY_MODE_READONLY; 1.440 + return false; 1.441 +} 1.442 + 1.443 +static bool 1.444 +_try_writable (hb_blob_t *blob) 1.445 +{ 1.446 + if (blob->immutable) 1.447 + return false; 1.448 + 1.449 + if (blob->mode == HB_MEMORY_MODE_WRITABLE) 1.450 + return true; 1.451 + 1.452 + if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob)) 1.453 + return true; 1.454 + 1.455 + if (blob->mode == HB_MEMORY_MODE_WRITABLE) 1.456 + return true; 1.457 + 1.458 + 1.459 + DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data); 1.460 + 1.461 + char *new_data; 1.462 + 1.463 + new_data = (char *) malloc (blob->length); 1.464 + if (unlikely (!new_data)) 1.465 + return false; 1.466 + 1.467 + DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data); 1.468 + 1.469 + memcpy (new_data, blob->data, blob->length); 1.470 + _hb_blob_destroy_user_data (blob); 1.471 + blob->mode = HB_MEMORY_MODE_WRITABLE; 1.472 + blob->data = new_data; 1.473 + blob->user_data = new_data; 1.474 + blob->destroy = free; 1.475 + 1.476 + return true; 1.477 +}