OLD | NEW |
(Empty) | |
| 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 */ |
| 26 |
| 27 #include "hb-private.hh" |
| 28 |
| 29 #include "hb-blob.h" |
| 30 #include "hb-object-private.hh" |
| 31 |
| 32 #ifdef HAVE_SYS_MMAN_H |
| 33 #ifdef HAVE_UNISTD_H |
| 34 #include <unistd.h> |
| 35 #endif /* HAVE_UNISTD_H */ |
| 36 #include <sys/mman.h> |
| 37 #endif /* HAVE_SYS_MMAN_H */ |
| 38 |
| 39 #include <stdio.h> |
| 40 #include <errno.h> |
| 41 |
| 42 |
| 43 |
| 44 #ifndef HB_DEBUG_BLOB |
| 45 #define HB_DEBUG_BLOB (HB_DEBUG+0) |
| 46 #endif |
| 47 |
| 48 |
| 49 struct _hb_blob_t { |
| 50 hb_object_header_t header; |
| 51 |
| 52 bool immutable; |
| 53 |
| 54 const char *data; |
| 55 unsigned int length; |
| 56 hb_memory_mode_t mode; |
| 57 |
| 58 void *user_data; |
| 59 hb_destroy_func_t destroy; |
| 60 }; |
| 61 |
| 62 static hb_blob_t _hb_blob_nil = { |
| 63 HB_OBJECT_HEADER_STATIC, |
| 64 |
| 65 TRUE, /* immutable */ |
| 66 |
| 67 NULL, /* data */ |
| 68 0, /* length */ |
| 69 HB_MEMORY_MODE_READONLY, /* mode */ |
| 70 |
| 71 NULL, /* user_data */ |
| 72 NULL /* destroy */ |
| 73 }; |
| 74 |
| 75 |
| 76 static bool _try_writable (hb_blob_t *blob); |
| 77 |
| 78 static void |
| 79 _hb_blob_destroy_user_data (hb_blob_t *blob) |
| 80 { |
| 81 if (blob->destroy) { |
| 82 blob->destroy (blob->user_data); |
| 83 blob->user_data = NULL; |
| 84 blob->destroy = NULL; |
| 85 } |
| 86 } |
| 87 |
| 88 hb_blob_t * |
| 89 hb_blob_create (const char *data, |
| 90 unsigned int length, |
| 91 hb_memory_mode_t mode, |
| 92 void *user_data, |
| 93 hb_destroy_func_t destroy) |
| 94 { |
| 95 hb_blob_t *blob; |
| 96 |
| 97 if (!length || !(blob = hb_object_create<hb_blob_t> ())) { |
| 98 if (destroy) |
| 99 destroy (user_data); |
| 100 return &_hb_blob_nil; |
| 101 } |
| 102 |
| 103 blob->data = data; |
| 104 blob->length = length; |
| 105 blob->mode = mode; |
| 106 |
| 107 blob->user_data = user_data; |
| 108 blob->destroy = destroy; |
| 109 |
| 110 if (blob->mode == HB_MEMORY_MODE_DUPLICATE) { |
| 111 blob->mode = HB_MEMORY_MODE_READONLY; |
| 112 if (!_try_writable (blob)) { |
| 113 hb_blob_destroy (blob); |
| 114 return &_hb_blob_nil; |
| 115 } |
| 116 } |
| 117 |
| 118 return blob; |
| 119 } |
| 120 |
| 121 hb_blob_t * |
| 122 hb_blob_create_sub_blob (hb_blob_t *parent, |
| 123 unsigned int offset, |
| 124 unsigned int length) |
| 125 { |
| 126 hb_blob_t *blob; |
| 127 |
| 128 if (!length || offset >= parent->length) |
| 129 return &_hb_blob_nil; |
| 130 |
| 131 hb_blob_make_immutable (parent); |
| 132 |
| 133 blob = hb_blob_create (parent->data + offset, |
| 134 MIN (length, parent->length - offset), |
| 135 parent->mode, |
| 136 hb_blob_reference (parent), |
| 137 (hb_destroy_func_t) hb_blob_destroy); |
| 138 |
| 139 return blob; |
| 140 } |
| 141 |
| 142 hb_blob_t * |
| 143 hb_blob_get_empty (void) |
| 144 { |
| 145 return &_hb_blob_nil; |
| 146 } |
| 147 |
| 148 hb_blob_t * |
| 149 hb_blob_reference (hb_blob_t *blob) |
| 150 { |
| 151 return hb_object_reference (blob); |
| 152 } |
| 153 |
| 154 void |
| 155 hb_blob_destroy (hb_blob_t *blob) |
| 156 { |
| 157 if (!hb_object_destroy (blob)) return; |
| 158 |
| 159 _hb_blob_destroy_user_data (blob); |
| 160 |
| 161 free (blob); |
| 162 } |
| 163 |
| 164 hb_bool_t |
| 165 hb_blob_set_user_data (hb_blob_t *blob, |
| 166 hb_user_data_key_t *key, |
| 167 void * data, |
| 168 hb_destroy_func_t destroy, |
| 169 hb_bool_t replace) |
| 170 { |
| 171 return hb_object_set_user_data (blob, key, data, destroy, replace); |
| 172 } |
| 173 |
| 174 void * |
| 175 hb_blob_get_user_data (hb_blob_t *blob, |
| 176 hb_user_data_key_t *key) |
| 177 { |
| 178 return hb_object_get_user_data (blob, key); |
| 179 } |
| 180 |
| 181 |
| 182 void |
| 183 hb_blob_make_immutable (hb_blob_t *blob) |
| 184 { |
| 185 if (hb_object_is_inert (blob)) |
| 186 return; |
| 187 |
| 188 blob->immutable = TRUE; |
| 189 } |
| 190 |
| 191 hb_bool_t |
| 192 hb_blob_is_immutable (hb_blob_t *blob) |
| 193 { |
| 194 return blob->immutable; |
| 195 } |
| 196 |
| 197 |
| 198 unsigned int |
| 199 hb_blob_get_length (hb_blob_t *blob) |
| 200 { |
| 201 return blob->length; |
| 202 } |
| 203 |
| 204 const char * |
| 205 hb_blob_get_data (hb_blob_t *blob, unsigned int *length) |
| 206 { |
| 207 if (length) |
| 208 *length = blob->length; |
| 209 |
| 210 return blob->data; |
| 211 } |
| 212 |
| 213 char * |
| 214 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) |
| 215 { |
| 216 if (!_try_writable (blob)) { |
| 217 if (length) |
| 218 *length = 0; |
| 219 |
| 220 return NULL; |
| 221 } |
| 222 |
| 223 if (length) |
| 224 *length = blob->length; |
| 225 |
| 226 return const_cast<char *> (blob->data); |
| 227 } |
| 228 |
| 229 |
| 230 static hb_bool_t |
| 231 _try_make_writable_inplace_unix (hb_blob_t *blob) |
| 232 { |
| 233 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) |
| 234 uintptr_t pagesize = -1, mask, length; |
| 235 const char *addr; |
| 236 |
| 237 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) |
| 238 pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE); |
| 239 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) |
| 240 pagesize = (uintptr_t) sysconf (_SC_PAGESIZE); |
| 241 #elif defined(HAVE_GETPAGESIZE) |
| 242 pagesize = (uintptr_t) getpagesize (); |
| 243 #endif |
| 244 |
| 245 if ((uintptr_t) -1L == pagesize) { |
| 246 DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno)); |
| 247 return FALSE; |
| 248 } |
| 249 DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize); |
| 250 |
| 251 mask = ~(pagesize-1); |
| 252 addr = (const char *) (((uintptr_t) blob->data) & mask); |
| 253 length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1)
& mask) - addr; |
| 254 DEBUG_MSG_FUNC (BLOB, blob, |
| 255 "calling mprotect on [%p..%p] (%lu bytes)", |
| 256 addr, addr+length, (unsigned long) length); |
| 257 if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) { |
| 258 DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno)); |
| 259 return FALSE; |
| 260 } |
| 261 |
| 262 blob->mode = HB_MEMORY_MODE_WRITABLE; |
| 263 |
| 264 DEBUG_MSG_FUNC (BLOB, blob, |
| 265 "successfully made [%p..%p] (%lu bytes) writable\n", |
| 266 addr, addr+length, (unsigned long) length); |
| 267 return TRUE; |
| 268 #else |
| 269 return FALSE; |
| 270 #endif |
| 271 } |
| 272 |
| 273 static bool |
| 274 _try_writable_inplace (hb_blob_t *blob) |
| 275 { |
| 276 DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n"); |
| 277 |
| 278 if (_try_make_writable_inplace_unix (blob)) |
| 279 return TRUE; |
| 280 |
| 281 DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n"); |
| 282 |
| 283 /* Failed to make writable inplace, mark that */ |
| 284 blob->mode = HB_MEMORY_MODE_READONLY; |
| 285 return FALSE; |
| 286 } |
| 287 |
| 288 static bool |
| 289 _try_writable (hb_blob_t *blob) |
| 290 { |
| 291 if (blob->immutable) |
| 292 return FALSE; |
| 293 |
| 294 if (blob->mode == HB_MEMORY_MODE_WRITABLE) |
| 295 return TRUE; |
| 296 |
| 297 if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_i
nplace (blob)) |
| 298 return TRUE; |
| 299 |
| 300 if (blob->mode == HB_MEMORY_MODE_WRITABLE) |
| 301 return TRUE; |
| 302 |
| 303 |
| 304 DEBUG_MSG_FUNC (BLOB, blob, "currect data is -> %p\n", blob->data); |
| 305 |
| 306 char *new_data; |
| 307 |
| 308 new_data = (char *) malloc (blob->length); |
| 309 if (unlikely (!new_data)) |
| 310 return FALSE; |
| 311 |
| 312 DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data); |
| 313 |
| 314 memcpy (new_data, blob->data, blob->length); |
| 315 _hb_blob_destroy_user_data (blob); |
| 316 blob->mode = HB_MEMORY_MODE_WRITABLE; |
| 317 blob->data = new_data; |
| 318 blob->user_data = new_data; |
| 319 blob->destroy = free; |
| 320 |
| 321 return TRUE; |
| 322 } |
| 323 |
| 324 |
OLD | NEW |