1 /* The DOM node handling */
13 #include "dom/string.h"
14 #include "util/hash.h"
15 #include "util/memory.h"
18 static void done_dom_node_data(struct dom_node
*node
);
22 #define DOM_NODE_LIST_GRANULARITY 0x7
24 #define DOM_NODE_LIST_BLOCK_SIZE \
25 (ALIGN_MEMORY_SIZE(1, DOM_NODE_LIST_GRANULARITY) * sizeof(struct dom_node *))
27 /* The node list struct has one node pointer */
28 #define DOM_NODE_LIST_SIZE(size) \
29 ((size - 1) * sizeof(struct dom_node *) + sizeof(struct dom_node_list))
31 static inline struct dom_node_list
*
32 realloc_dom_node_list(struct dom_node_list
**oldlist
)
34 struct dom_node_list
*list
= *oldlist
;
35 size_t size
= list
? list
->size
: 0;
36 size_t oldsize
= ALIGN_MEMORY_SIZE(size
, DOM_NODE_LIST_GRANULARITY
);
37 size_t newsize
= ALIGN_MEMORY_SIZE(size
+ 1, DOM_NODE_LIST_GRANULARITY
);
39 if (newsize
<= oldsize
) return list
;
41 list
= mem_realloc(list
, DOM_NODE_LIST_SIZE(newsize
));
42 if (!list
) return NULL
;
44 /* If this is the first reallocation clear the size */
45 if (!size
) list
->size
= 0;
47 /* Clear the new block of entries */
48 memset(&list
->entries
[oldsize
], 0, DOM_NODE_LIST_BLOCK_SIZE
);
55 struct dom_node_list
*
56 add_to_dom_node_list(struct dom_node_list
**list_ptr
,
57 struct dom_node
*node
, int position
)
59 struct dom_node_list
*list
;
61 assert(list_ptr
&& node
);
63 list
= realloc_dom_node_list(list_ptr
);
64 if (!list
) return NULL
;
66 assertm(position
< 0 || position
<= list
->size
,
67 "position out of bound %d > %zu", position
, list
->size
);
70 position
= list
->size
;
72 } else if (position
< list
->size
) {
73 /* Make room if we have to add the node in the middle of the list */
74 struct dom_node
**offset
= &list
->entries
[position
];
75 size_t size
= (list
->size
- position
) * sizeof(*offset
);
77 memmove(offset
+ 1, offset
, size
);
81 list
->entries
[position
] = node
;
87 del_from_dom_node_list(struct dom_node_list
*list
, struct dom_node
*node
)
89 struct dom_node
*entry
;
94 foreach_dom_node (list
, entry
, i
) {
97 if (entry
!= node
) continue;
99 successors
= list
->size
- (i
+ 1);
101 memmove(&list
->entries
[i
], &list
->entries
[i
+1],
102 sizeof(*list
->entries
) * successors
);
108 done_dom_node_list(struct dom_node_list
*list
)
110 struct dom_node
*node
;
115 foreach_dom_node (list
, node
, i
) {
116 /* Avoid that the node start messing with the node list. */
117 done_dom_node_data(node
);
126 struct dom_node_search
{
127 struct dom_node
*key
;
128 unsigned int from
, pos
, to
;
131 #define INIT_DOM_NODE_SEARCH(key, list) \
132 { (key), -1, 0, (list)->size, }
135 dom_node_casecmp(struct dom_node
*node1
, struct dom_node
*node2
)
137 if (node1
->type
== node2
->type
) {
138 switch (node1
->type
) {
139 case DOM_NODE_ELEMENT
:
140 if (node1
->data
.element
.type
&& node2
->data
.element
.type
)
141 return node1
->data
.element
.type
- node2
->data
.element
.type
;
144 case DOM_NODE_ATTRIBUTE
:
145 if (node1
->data
.attribute
.type
&& node2
->data
.attribute
.type
)
146 return node1
->data
.attribute
.type
- node2
->data
.attribute
.type
;
154 return dom_string_casecmp(&node1
->string
, &node2
->string
);
158 get_bsearch_position(struct dom_node_list
*list
, int from
, int to
)
160 int pos
= from
+ ((to
- from
) / 2);
162 assertm(0 <= pos
&& pos
< list
->size
, "pos %d", pos
);
166 #define has_bsearch_node(from, to) ((from) + 1 < (to))
168 static inline struct dom_node
*
169 dom_node_list_bsearch(struct dom_node_search
*search
, struct dom_node_list
*list
)
171 assert(has_bsearch_node(search
->from
, search
->to
));
174 int pos
= get_bsearch_position(list
, search
->from
, search
->to
);
175 struct dom_node
*node
= list
->entries
[pos
];
176 int difference
= dom_node_casecmp(search
->key
, node
);
180 if (!difference
) return node
;
182 if (difference
< 0) {
183 search
->to
= search
->pos
;
185 search
->from
= search
->pos
;
188 } while (has_bsearch_node(search
->from
, search
->to
));
194 get_dom_node_map_index(struct dom_node_list
*list
, struct dom_node
*node
)
196 struct dom_node_search search
= INIT_DOM_NODE_SEARCH(node
, list
);
197 struct dom_node
*match
= dom_node_list_bsearch(&search
, list
);
199 return match
? search
.pos
: search
.to
;
203 get_dom_node_map_entry(struct dom_node_list
*list
, enum dom_node_type type
,
204 uint16_t subtype
, struct dom_string
*name
)
206 struct dom_node node
= { type
, 0, INIT_DOM_STRING(name
->string
, name
->length
) };
207 struct dom_node_search search
= INIT_DOM_NODE_SEARCH(&node
, list
);
210 /* Set the subtype */
212 case DOM_NODE_ELEMENT
:
213 node
.data
.element
.type
= subtype
;
215 case DOM_NODE_ATTRIBUTE
:
216 node
.data
.attribute
.type
= subtype
;
218 case DOM_NODE_PROCESSING_INSTRUCTION
:
219 node
.data
.proc_instruction
.type
= subtype
;
226 return dom_node_list_bsearch(&search
, list
);
230 get_dom_node_list_pos(struct dom_node_list
*list
, struct dom_node
*node
)
232 struct dom_node
*entry
;
237 foreach_dom_node (list
, entry
, i
) {
246 get_dom_node_list_index(struct dom_node
*parent
, struct dom_node
*node
)
248 struct dom_node_list
**list
= get_dom_node_list(parent
, node
);
250 return list
? get_dom_node_list_pos(*list
, node
) : -1;
254 get_dom_node_prev(struct dom_node
*node
)
256 struct dom_node_list
**list
;
259 assert(node
->parent
);
261 list
= get_dom_node_list(node
->parent
, node
);
262 if (!list
) return NULL
;
264 index
= get_dom_node_list_pos(*list
, node
);
266 return (*list
)->entries
[index
- 1];
272 get_dom_node_next(struct dom_node
*node
)
274 struct dom_node_list
**list
;
277 assert(node
->parent
);
279 list
= get_dom_node_list(node
->parent
, node
);
280 if (!list
) return NULL
;
282 index
= get_dom_node_list_pos(*list
, node
);
283 if (index
+ 1 < (*list
)->size
)
284 return (*list
)->entries
[index
+ 1];
290 get_dom_node_child(struct dom_node
*parent
, enum dom_node_type type
,
293 struct dom_node_list
**list
;
294 struct dom_node
*node
;
297 list
= get_dom_node_list_by_type(parent
, type
);
298 if (!list
) return NULL
;
300 foreach_dom_node (*list
, node
, index
) {
301 if (node
->type
!= type
)
304 if (!subtype
) return node
;
307 case DOM_NODE_ELEMENT
:
308 if (node
->data
.element
.type
== subtype
)
312 case DOM_NODE_ATTRIBUTE
:
313 if (node
->data
.attribute
.type
== subtype
)
317 case DOM_NODE_PROCESSING_INSTRUCTION
:
318 if (node
->data
.attribute
.type
== subtype
)
336 unsigned char *file
, int line
,
338 struct dom_node
*parent
, enum dom_node_type type
,
339 struct dom_string
*string
, int allocated
)
342 struct dom_node
*node
= debug_mem_calloc(file
, line
, 1, sizeof(*node
));
344 struct dom_node
*node
= mem_calloc(1, sizeof(*node
));
347 if (!node
) return NULL
;
350 node
->parent
= parent
;
352 /* Make it possible to add a node to a parent without allocating the
354 if (allocated
>= 0) {
355 node
->allocated
= !!allocated
;
357 node
->allocated
= parent
->allocated
;
360 if (node
->allocated
) {
361 if (!init_dom_string(&node
->string
, string
->string
, string
->length
)) {
366 copy_dom_string(&node
->string
, string
);
370 struct dom_node_list
**list
= get_dom_node_list(parent
, node
);
371 int sort
= (type
== DOM_NODE_ATTRIBUTE
);
374 assertm(list
!= NULL
, "Adding node %d to bad parent %d",
375 node
->type
, parent
->type
);
377 index
= *list
&& (*list
)->size
> 0 && sort
378 ? get_dom_node_map_index(*list
, node
) : -1;
380 if (!add_to_dom_node_list(list
, node
, index
)) {
390 done_dom_node_data(struct dom_node
*node
)
392 union dom_node_data
*data
;
398 switch (node
->type
) {
399 case DOM_NODE_ATTRIBUTE
:
401 done_dom_string(&data
->attribute
.value
);
404 case DOM_NODE_DOCUMENT
:
405 if (data
->document
.children
)
406 done_dom_node_list(data
->document
.children
);
409 case DOM_NODE_ELEMENT
:
410 if (data
->element
.children
)
411 done_dom_node_list(data
->element
.children
);
413 if (data
->element
.map
)
414 done_dom_node_list(data
->element
.map
);
417 case DOM_NODE_PROCESSING_INSTRUCTION
:
418 if (data
->proc_instruction
.map
)
419 done_dom_node_list(data
->proc_instruction
.map
);
421 done_dom_string(&data
->proc_instruction
.instruction
);
429 done_dom_string(&node
->string
);
434 done_dom_node(struct dom_node
*node
)
439 struct dom_node
*parent
= node
->parent
;
440 union dom_node_data
*data
= &parent
->data
;
442 switch (parent
->type
) {
443 case DOM_NODE_DOCUMENT
:
444 del_from_dom_node_list(data
->document
.children
, node
);
447 case DOM_NODE_ELEMENT
:
448 del_from_dom_node_list(data
->element
.children
, node
);
449 del_from_dom_node_list(data
->element
.map
, node
);
452 case DOM_NODE_PROCESSING_INSTRUCTION
:
453 del_from_dom_node_list(data
->proc_instruction
.map
, node
);
461 done_dom_node_data(node
);
464 #define set_node_name(name, namelen, str) \
465 do { (name) = (str); (namelen) = sizeof(str) - 1; } while (0)
468 get_dom_node_name(struct dom_node
*node
)
470 static struct dom_string cdata_section_str
= STATIC_DOM_STRING("#cdata-section");
471 static struct dom_string comment_str
= STATIC_DOM_STRING("#comment");
472 static struct dom_string document_str
= STATIC_DOM_STRING("#document");
473 static struct dom_string document_fragment_str
= STATIC_DOM_STRING("#document-fragment");
474 static struct dom_string text_str
= STATIC_DOM_STRING("#text");
478 switch (node
->type
) {
479 case DOM_NODE_CDATA_SECTION
:
480 return &cdata_section_str
;
482 case DOM_NODE_COMMENT
:
485 case DOM_NODE_DOCUMENT
:
486 return &document_str
;
488 case DOM_NODE_DOCUMENT_FRAGMENT
:
489 return &document_fragment_str
;
494 case DOM_NODE_ATTRIBUTE
:
495 case DOM_NODE_DOCUMENT_TYPE
:
496 case DOM_NODE_ELEMENT
:
497 case DOM_NODE_ENTITY
:
498 case DOM_NODE_ENTITY_REFERENCE
:
499 case DOM_NODE_NOTATION
:
500 case DOM_NODE_PROCESSING_INSTRUCTION
:
502 return &node
->string
;
507 get_dom_node_value(struct dom_node
*node
)
511 switch (node
->type
) {
512 case DOM_NODE_ATTRIBUTE
:
513 return &node
->data
.attribute
.value
;
515 case DOM_NODE_PROCESSING_INSTRUCTION
:
516 return &node
->data
.proc_instruction
.instruction
;
518 case DOM_NODE_CDATA_SECTION
:
519 case DOM_NODE_COMMENT
:
521 return &node
->string
;
523 case DOM_NODE_ENTITY_REFERENCE
:
524 case DOM_NODE_NOTATION
:
525 case DOM_NODE_DOCUMENT
:
526 case DOM_NODE_DOCUMENT_FRAGMENT
:
527 case DOM_NODE_DOCUMENT_TYPE
:
528 case DOM_NODE_ELEMENT
:
529 case DOM_NODE_ENTITY
:
536 get_dom_node_type_name(enum dom_node_type type
)
538 static struct dom_string dom_node_type_names
[DOM_NODES
] = {
539 INIT_DOM_STRING(NULL
, 0),
540 /* DOM_NODE_ELEMENT */ STATIC_DOM_STRING("element"),
541 /* DOM_NODE_ATTRIBUTE */ STATIC_DOM_STRING("attribute"),
542 /* DOM_NODE_TEXT */ STATIC_DOM_STRING("text"),
543 /* DOM_NODE_CDATA_SECTION */ STATIC_DOM_STRING("cdata-section"),
544 /* DOM_NODE_ENTITY_REFERENCE */ STATIC_DOM_STRING("entity-reference"),
545 /* DOM_NODE_ENTITY */ STATIC_DOM_STRING("entity"),
546 /* DOM_NODE_PROCESSING_INSTRUCTION */ STATIC_DOM_STRING("proc-instruction"),
547 /* DOM_NODE_COMMENT */ STATIC_DOM_STRING("comment"),
548 /* DOM_NODE_DOCUMENT */ STATIC_DOM_STRING("document"),
549 /* DOM_NODE_DOCUMENT_TYPE */ STATIC_DOM_STRING("document-type"),
550 /* DOM_NODE_DOCUMENT_FRAGMENT */ STATIC_DOM_STRING("document-fragment"),
551 /* DOM_NODE_NOTATION */ STATIC_DOM_STRING("notation"),
554 assert(type
< DOM_NODES
);
556 return &dom_node_type_names
[type
];