1 /*
2 * Copyright (C) 2021-2022 Alexander Borisov
3 *
4 * Author: Alexander Borisov <borisov@lexbor.com>
5 */
6
7 #include "lexbor/css/css.h"
8
9
10 typedef struct {
11 lexbor_str_t *str;
12 lexbor_mraw_t *mraw;
13 }
14 lxb_css_str_ctx_t;
15
16
17 static lxb_status_t
18 lxb_css_str_cb(const lxb_char_t *data, size_t len, void *cb_ctx);
19
20
21 lxb_css_memory_t *
lxb_css_memory_create(void)22 lxb_css_memory_create(void)
23 {
24 return lexbor_calloc(1, sizeof(lxb_css_memory_t));
25 }
26
27 lxb_status_t
lxb_css_memory_init(lxb_css_memory_t * memory,size_t prepare_count)28 lxb_css_memory_init(lxb_css_memory_t *memory, size_t prepare_count)
29 {
30 lxb_status_t status;
31
32 static const size_t size_mem = lexbor_max(sizeof(lxb_css_selector_t),
33 sizeof(lxb_css_selector_list_t));
34
35 if (memory == NULL) {
36 return LXB_STATUS_ERROR_INCOMPLETE_OBJECT;
37 }
38
39 if (prepare_count < 64) {
40 prepare_count = 64;
41 }
42
43 if (memory->objs == NULL) {
44 memory->objs = lexbor_dobject_create();
45 status = lexbor_dobject_init(memory->objs, prepare_count, size_mem);
46 if (status != LXB_STATUS_OK) {
47 goto failed;
48 }
49 }
50
51 if (memory->tree == NULL) {
52 prepare_count = prepare_count * 96;
53
54 memory->tree = lexbor_mraw_create();
55 status = lexbor_mraw_init(memory->tree, prepare_count);
56 if (status != LXB_STATUS_OK) {
57 goto failed;
58 }
59 }
60
61 if (memory->mraw == NULL) {
62 memory->mraw = lexbor_mraw_create();
63 status = lexbor_mraw_init(memory->mraw, 4096);
64 if (status != LXB_STATUS_OK) {
65 goto failed;
66 }
67 }
68
69 memory->ref_count = 1;
70
71 return LXB_STATUS_OK;
72
73 failed:
74
75 (void) lxb_css_memory_destroy(memory, false);
76
77 return status;
78 }
79
80 void
lxb_css_memory_clean(lxb_css_memory_t * memory)81 lxb_css_memory_clean(lxb_css_memory_t *memory)
82 {
83 if (memory->objs != NULL) {
84 lexbor_dobject_clean(memory->objs);
85 }
86
87 if (memory->mraw != NULL) {
88 lexbor_mraw_clean(memory->mraw);
89 }
90
91 if (memory->tree != NULL) {
92 lexbor_mraw_clean(memory->tree);
93 }
94 }
95
96 lxb_css_memory_t *
lxb_css_memory_destroy(lxb_css_memory_t * memory,bool self_destroy)97 lxb_css_memory_destroy(lxb_css_memory_t *memory, bool self_destroy)
98 {
99 if (memory == NULL) {
100 return NULL;
101 }
102
103 if (memory->objs != NULL) {
104 memory->objs = lexbor_dobject_destroy(memory->objs, true);
105 }
106
107 if (memory->mraw != NULL) {
108 memory->mraw = lexbor_mraw_destroy(memory->mraw, true);
109 }
110
111 if (memory->tree != NULL) {
112 memory->tree = lexbor_mraw_destroy(memory->tree, true);
113 }
114
115 if (self_destroy) {
116 return lexbor_free(memory);
117 }
118
119 return memory;
120 }
121
122 lxb_css_memory_t *
lxb_css_memory_ref_inc(lxb_css_memory_t * memory)123 lxb_css_memory_ref_inc(lxb_css_memory_t *memory)
124 {
125 if (SIZE_MAX - memory->ref_count == 0) {
126 return NULL;
127 }
128
129 memory->ref_count++;
130
131 return memory;
132 }
133
134 void
lxb_css_memory_ref_dec(lxb_css_memory_t * memory)135 lxb_css_memory_ref_dec(lxb_css_memory_t *memory)
136 {
137 if (memory->ref_count > 0) {
138 memory->ref_count--;
139 }
140 }
141
142 lxb_css_memory_t *
lxb_css_memory_ref_dec_destroy(lxb_css_memory_t * memory)143 lxb_css_memory_ref_dec_destroy(lxb_css_memory_t *memory)
144 {
145 if (memory->ref_count > 0) {
146 memory->ref_count--;
147 }
148
149 if (memory->ref_count == 0) {
150 return lxb_css_memory_destroy(memory, true);
151 }
152
153 return memory;
154 }
155
156 lxb_status_t
lxb_css_make_data(lxb_css_parser_t * parser,lexbor_str_t * str,uintptr_t begin,uintptr_t end)157 lxb_css_make_data(lxb_css_parser_t *parser, lexbor_str_t *str,
158 uintptr_t begin, uintptr_t end)
159 {
160 size_t length, offlen, len;
161 const lxb_char_t *pos;
162 const lexbor_str_t *tmp;
163
164 tmp = &parser->str;
165
166 offlen = begin - parser->offset;
167 length = end - begin;
168
169 if (str->data == NULL) {
170 (void) lexbor_str_init(str, parser->memory->mraw, length);
171 if (str->data == NULL) {
172 return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
173 }
174 }
175
176 if (tmp->length > offlen) {
177 len = tmp->length - offlen;
178
179 if (len >= length) {
180 memcpy(str->data + str->length, tmp->data + offlen, length);
181 goto done;
182 }
183 else {
184 memcpy(str->data + str->length, tmp->data + offlen, len);
185 }
186
187 str->length += len;
188
189 pos = parser->pos;
190 length -= len;
191 }
192 else {
193 pos = parser->pos + (offlen - tmp->length);
194 }
195
196 memcpy(str->data + str->length, pos, length);
197
198 done:
199
200 str->length += length;
201 str->data[str->length] = '\0';
202
203 return LXB_STATUS_OK;
204 }
205
206 lxb_char_t *
lxb_css_serialize_char_handler(const void * style,lxb_css_style_serialize_f cb,size_t * out_length)207 lxb_css_serialize_char_handler(const void *style, lxb_css_style_serialize_f cb,
208 size_t *out_length)
209 {
210 size_t length = 0;
211 lxb_status_t status;
212 lexbor_str_t str;
213
214 status = cb(style, lexbor_serialize_length_cb, &length);
215 if (status != LXB_STATUS_OK) {
216 goto failed;
217 }
218
219 /* + 1 == '\0' */
220 str.data = lexbor_malloc(length + 1);
221 if (str.data == NULL) {
222 goto failed;
223 }
224
225 str.length = 0;
226
227 status = cb(style, lexbor_serialize_copy_cb, &str);
228 if (status != LXB_STATUS_OK) {
229 lexbor_free(str.data);
230 goto failed;
231 }
232
233 str.data[str.length] = '\0';
234
235 if (out_length != NULL) {
236 *out_length = str.length;
237 }
238
239 return str.data;
240
241 failed:
242
243 if (out_length != NULL) {
244 *out_length = 0;
245 }
246
247 return NULL;
248 }
249
250 lxb_status_t
lxb_css_serialize_str_handler(const void * style,lexbor_str_t * str,lexbor_mraw_t * mraw,lxb_css_style_serialize_f cb)251 lxb_css_serialize_str_handler(const void *style, lexbor_str_t *str,
252 lexbor_mraw_t *mraw,
253 lxb_css_style_serialize_f cb)
254 {
255 lxb_css_str_ctx_t ctx;
256
257 ctx.str = str;
258 ctx.mraw = mraw;
259
260 if (str->data == NULL) {
261 lexbor_str_init(str, mraw, 1);
262 if (str->data == NULL) {
263 return LXB_STATUS_ERROR_MEMORY_ALLOCATION;
264 }
265 }
266
267 return cb(style, lxb_css_str_cb, &ctx);
268 }
269
270 static lxb_status_t
lxb_css_str_cb(const lxb_char_t * data,size_t len,void * cb_ctx)271 lxb_css_str_cb(const lxb_char_t *data, size_t len, void *cb_ctx)
272 {
273 lxb_char_t *ptr;
274 lxb_css_str_ctx_t *ctx = (lxb_css_str_ctx_t *) cb_ctx;
275
276 ptr = lexbor_str_append(ctx->str, ctx->mraw, data, len);
277
278 return (ptr != NULL) ? LXB_STATUS_OK : LXB_STATUS_ERROR_MEMORY_ALLOCATION;
279 }
280