add explicit freetype2 linking
[charfbuzz.git] / hb-blob.c
blob6cc79394dfa9884d604a6e958268d841c370f3f1
1 /*
2 Port from c++ is protected by a GNU Lesser GPLv3
3 Copyright © 2013 Sylvain BERTRAND <sylvain.bertrand@gmail.com>
4 */
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <sys/mman.h>
8 #include <string.h>
10 #include "hb.h"
11 #include "hb-private.h"
12 #include "hb-atomic-private.h"
13 #include "hb-open-file-private.h"
14 #include "hb-blob-private.h"
16 struct hb_blob_t {
17 atomic_int32_t ref_cnt;
18 hb_bool_t immutable;
20 const char *data;
21 unsigned length;
22 hb_memory_mode_t mode;
24 void *user_data;
25 hb_destroy_func_t destroy;
28 /*XXX:should go in lib "global init"*/
29 static hb_blob_t hb_blob_nil = {
30 REF_CNT_INVALID_VAL, /*ref_cnt */
31 TRUE, /*immutable */
32 NULL, /*data */
33 0, /*length */
34 HB_MEMORY_MODE_READONLY, /*mode */
35 NULL, /*user_data */
36 NULL /*destroy */
39 hb_blob_t *hb_blob_get_empty(void)
41 return &hb_blob_nil;
44 hb_blob_t *hb_blob_reference(hb_blob_t * blob)
46 if (hb_atomic_int32_get(&blob->ref_cnt) != REF_CNT_INVALID_VAL)
47 hb_atomic_int32_add(&blob->ref_cnt, 1);
48 return blob;
51 void hb_blob_make_immutable(hb_blob_t * blob)
53 if (hb_atomic_int32_get(&blob->ref_cnt) == REF_CNT_INVALID_VAL)
54 return;
55 blob->immutable = TRUE;
58 unsigned hb_blob_get_length(hb_blob_t * blob)
60 return blob->length;
63 const char *hb_blob_get_data(hb_blob_t * blob, unsigned *length)
65 if (length)
66 *length = blob->length;
67 return blob->data;
70 static hb_bool_t try_make_writable_inplace_unix(hb_blob_t * blob)
72 uintptr_t pagesize, mask, length;
73 const char *addr;
75 pagesize = (uintptr_t) sysconf(_SC_PAGESIZE);
77 if ((uintptr_t) - 1L == pagesize)
78 return FALSE;
80 mask = ~(pagesize - 1);
81 addr = (const char *)(((uintptr_t) blob->data) & mask);
82 length =
83 (const char
84 *)(((uintptr_t) blob->data + blob->length + pagesize - 1)
85 & mask) - addr;
86 if (-1 == mprotect((void *)addr, length, PROT_READ | PROT_WRITE))
87 return FALSE;
89 blob->mode = HB_MEMORY_MODE_WRITABLE;
90 return TRUE;
93 static hb_bool_t try_writable_inplace(hb_blob_t * blob)
95 if (try_make_writable_inplace_unix(blob))
96 return TRUE;
98 /*Failed to make writable inplace, mark that */
99 blob->mode = HB_MEMORY_MODE_READONLY;
100 return FALSE;
103 static void hb_blob_destroy_user_data(hb_blob_t * blob)
105 if (blob->destroy) {
106 blob->destroy(blob->user_data);
107 blob->user_data = NULL;
108 blob->destroy = NULL;
112 static hb_bool_t try_writable(hb_blob_t * blob)
114 char *new_data;
116 if (blob->immutable)
117 return FALSE;
119 if (blob->mode == HB_MEMORY_MODE_WRITABLE)
120 return TRUE;
122 if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
123 && try_writable_inplace(blob))
124 return TRUE;
126 if (blob->mode == HB_MEMORY_MODE_WRITABLE)
127 return TRUE;
129 new_data = malloc(blob->length);
130 if (!new_data)
131 return FALSE;
133 memcpy(new_data, blob->data, blob->length);
134 hb_blob_destroy_user_data(blob);
135 blob->mode = HB_MEMORY_MODE_WRITABLE;
136 blob->data = new_data;
137 blob->user_data = new_data;
138 blob->destroy = free;
139 return TRUE;
142 void hb_blob_destroy(hb_blob_t * blob)
144 if (!blob)
145 return;
146 if (hb_atomic_int32_get(&blob->ref_cnt) == REF_CNT_INVALID_VAL)
147 return;
148 hb_atomic_int32_add(&blob->ref_cnt, -1);
149 if (hb_atomic_int32_get(&blob->ref_cnt) > 0)
150 return;
151 hb_atomic_int32_set(&blob->ref_cnt, REF_CNT_INVALID_VAL);
153 hb_blob_destroy_user_data(blob);
154 free(blob);
157 hb_blob_t *hb_blob_create_sub_blob(hb_blob_t * parent,
158 unsigned offset, unsigned length)
160 hb_blob_t *blob;
162 if (!length || offset >= parent->length)
163 return hb_blob_get_empty();
165 hb_blob_make_immutable(parent);
167 blob = hb_blob_create(parent->data + offset,
168 MIN(length, parent->length - offset),
169 HB_MEMORY_MODE_READONLY,
170 hb_blob_reference(parent),
171 (hb_destroy_func_t) hb_blob_destroy);
172 return blob;
175 hb_blob_t *hb_blob_create(const char *data, unsigned length,
176 hb_memory_mode_t mode, void *user_data,
177 hb_destroy_func_t destroy)
179 hb_blob_t *blob = calloc(1, sizeof(*blob));
180 if (!length || !blob) {
181 if (blob)
182 free(blob);
183 if (destroy)
184 destroy(user_data);
185 return hb_blob_get_empty();
187 hb_atomic_int32_set(&blob->ref_cnt, 1);
188 blob->immutable = FALSE;
190 blob->data = data;
191 blob->length = length;
192 blob->mode = mode;
194 blob->user_data = user_data;
195 blob->destroy = destroy;
197 if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
198 blob->mode = HB_MEMORY_MODE_READONLY;
199 if (!try_writable(blob)) {
200 hb_blob_destroy(blob);
201 return hb_blob_get_empty();
204 return blob;
207 struct ot_fnt_file *hb_blob_lock_instance(hb_blob_t * blob)
209 const char *base;
211 hb_blob_make_immutable(blob);
212 base = hb_blob_get_data(blob, NULL);
213 return (struct ot_fnt_file *)base;