xref: /php-src/ext/dom/lexbor/lexbor/css/css.c (revision 7defc235)
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