1 /*
2 * This file is part of libdom.
3 * Licensed under the MIT License,
4 * http://www.opensource.org/licenses/mit-license.php
5 * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
6 * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
7 */
8
9 #include <assert.h>
10 #include <stdlib.h>
11
12 #include <dom/core/element.h>
13 #include <dom/core/node.h>
14 #include <dom/core/string.h>
15
16 #include "core/document.h"
17 #include "core/element.h"
18 #include "core/namednodemap.h"
19 #include "core/node.h"
20
21 #include "utils/utils.h"
22
23 /**
24 * DOM named node map
25 */
26 struct dom_namednodemap {
27 dom_document *owner; /**< Owning document */
28
29 void *priv; /**< Private data */
30
31 struct nnm_operation *opt; /**< The underlaid operation
32 * implementations */
33
34 uint32_t refcnt; /**< Reference count */
35 };
36
37 /**
38 * Create a namednodemap
39 *
40 * \param doc The owning document
41 * \param priv The private data of this dom_namednodemap
42 * \param opt The operation function pointer
43 * \param map Pointer to location to receive created map
44 * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
45 *
46 * ::head must be a node owned by ::doc and must be either an Element or
47 * DocumentType node.
48 *
49 * If ::head is of type Element, ::type must be DOM_ATTRIBUTE_NODE
50 * If ::head is of type DocumentType, ::type may be either
51 * DOM_ENTITY_NODE or DOM_NOTATION_NODE.
52 *
53 * The returned map will already be referenced, so the client need not
54 * explicitly reference it. The client must unref the map once it is
55 * finished with it.
56 */
_dom_namednodemap_create(dom_document * doc,void * priv,struct nnm_operation * opt,dom_namednodemap ** map)57 dom_exception _dom_namednodemap_create(dom_document *doc,
58 void *priv, struct nnm_operation *opt,
59 dom_namednodemap **map)
60 {
61 dom_namednodemap *m;
62
63 m = malloc(sizeof(dom_namednodemap));
64 if (m == NULL)
65 return DOM_NO_MEM_ERR;
66
67 m->owner = doc;
68
69 m->priv = priv;
70 m->opt = opt;
71
72 m->refcnt = 1;
73
74 *map = m;
75
76 return DOM_NO_ERR;
77 }
78
79 /**
80 * Claim a reference on a DOM named node map
81 *
82 * \param map The map to claim a reference on
83 */
dom_namednodemap_ref(dom_namednodemap * map)84 void dom_namednodemap_ref(dom_namednodemap *map)
85 {
86 assert(map != NULL);
87 map->refcnt++;
88 }
89
90 /**
91 * Release a reference on a DOM named node map
92 *
93 * \param map The map to release the reference from
94 *
95 * If the reference count reaches zero, any memory claimed by the
96 * map will be released
97 */
dom_namednodemap_unref(dom_namednodemap * map)98 void dom_namednodemap_unref(dom_namednodemap *map)
99 {
100 if (map == NULL)
101 return;
102
103 if (--map->refcnt == 0) {
104 /* Call the implementation specific destroy */
105 map->opt->namednodemap_destroy(map->priv);
106
107 /* Destroy the map object */
108 free(map);
109 }
110 }
111
112 /**
113 * Retrieve the length of a named node map
114 *
115 * \param map Map to retrieve length of
116 * \param length Pointer to location to receive length
117 * \return DOM_NO_ERR.
118 */
dom_namednodemap_get_length(dom_namednodemap * map,dom_ulong * length)119 dom_exception dom_namednodemap_get_length(dom_namednodemap *map,
120 dom_ulong *length)
121 {
122 assert(map->opt != NULL);
123 return map->opt->namednodemap_get_length(map->priv, length);
124 }
125
126 /**
127 * Retrieve an item by name from a named node map
128 *
129 * \param map The map to retrieve the item from
130 * \param name The name of the item to retrieve
131 * \param node Pointer to location to receive item
132 * \return DOM_NO_ERR.
133 *
134 * The returned node will have had its reference count increased. The client
135 * should unref the node once it has finished with it.
136 */
_dom_namednodemap_get_named_item(dom_namednodemap * map,dom_string * name,dom_node ** node)137 dom_exception _dom_namednodemap_get_named_item(dom_namednodemap *map,
138 dom_string *name, dom_node **node)
139 {
140 assert(map->opt != NULL);
141 return map->opt->namednodemap_get_named_item(map->priv, name, node);
142 }
143
144 /**
145 * Add a node to a named node map, replacing any matching existing node
146 *
147 * \param map The map to add to
148 * \param arg The node to add
149 * \param node Pointer to location to receive replaced node
150 * \return DOM_NO_ERR on success,
151 * DOM_WRONG_DOCUMENT_ERR if ::arg was created from a
152 * different document than ::map,
153 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly,
154 * DOM_INUSE_ATTRIBUTE_ERR if ::arg is an Attr that is
155 * already an attribute on another
156 * Element,
157 * DOM_HIERARCHY_REQUEST_ERR if the type of ::arg is not
158 * permitted as a member of ::map.
159 *
160 * ::arg's nodeName attribute will be used to store it in ::map. It will
161 * be accessible using the nodeName attribute as the key for lookup.
162 *
163 * Replacing a node by itself has no effect.
164 *
165 * The returned node will have had its reference count increased. The client
166 * should unref the node once it has finished with it.
167 */
_dom_namednodemap_set_named_item(dom_namednodemap * map,dom_node * arg,dom_node ** node)168 dom_exception _dom_namednodemap_set_named_item(dom_namednodemap *map,
169 dom_node *arg, dom_node **node)
170 {
171 assert(map->opt != NULL);
172 return map->opt->namednodemap_set_named_item(map->priv, arg, node);
173 }
174
175 /**
176 * Remove an item by name from a named node map
177 *
178 * \param map The map to remove from
179 * \param name The name of the item to remove
180 * \param node Pointer to location to receive removed item
181 * \return DOM_NO_ERR on success,
182 * DOM_NOT_FOUND_ERR if there is no node named ::name
183 * in ::map,
184 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly.
185 *
186 * The returned node will have had its reference count increased. The client
187 * should unref the node once it has finished with it.
188 */
_dom_namednodemap_remove_named_item(dom_namednodemap * map,dom_string * name,dom_node ** node)189 dom_exception _dom_namednodemap_remove_named_item(
190 dom_namednodemap *map, dom_string *name,
191 dom_node **node)
192 {
193 assert(map->opt != NULL);
194 return map->opt->namednodemap_remove_named_item(map->priv, name, node);
195 }
196
197 /**
198 * Retrieve an item from a named node map
199 *
200 * \param map The map to retrieve the item from
201 * \param index The map index to retrieve
202 * \param node Pointer to location to receive item
203 * \return DOM_NO_ERR.
204 *
205 * ::index is a zero-based index into ::map.
206 * ::index lies in the range [0, length-1]
207 *
208 * The returned node will have had its reference count increased. The client
209 * should unref the node once it has finished with it.
210 */
_dom_namednodemap_item(dom_namednodemap * map,dom_ulong index,dom_node ** node)211 dom_exception _dom_namednodemap_item(dom_namednodemap *map,
212 dom_ulong index, dom_node **node)
213 {
214 assert(map->opt != NULL);
215 return map->opt->namednodemap_item(map->priv, index, node);
216 }
217
218 /**
219 * Retrieve an item by namespace/localname from a named node map
220 *
221 * \param map The map to retrieve the item from
222 * \param namespace The namespace URI of the item to retrieve
223 * \param localname The local name of the node to retrieve
224 * \param node Pointer to location to receive item
225 * \return DOM_NO_ERR on success,
226 * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
227 * feature "XML" and the language exposed
228 * through the Document does not support
229 * Namespaces.
230 *
231 * The returned node will have had its reference count increased. The client
232 * should unref the node once it has finished with it.
233 */
_dom_namednodemap_get_named_item_ns(dom_namednodemap * map,dom_string * namespace,dom_string * localname,dom_node ** node)234 dom_exception _dom_namednodemap_get_named_item_ns(
235 dom_namednodemap *map, dom_string *namespace,
236 dom_string *localname, dom_node **node)
237 {
238 assert(map->opt != NULL);
239 return map->opt->namednodemap_get_named_item_ns(map->priv, namespace,
240 localname, node);
241 }
242
243 /**
244 * Add a node to a named node map, replacing any matching existing node
245 *
246 * \param map The map to add to
247 * \param arg The node to add
248 * \param node Pointer to location to receive replaced node
249 * \return DOM_NO_ERR on success,
250 * DOM_WRONG_DOCUMENT_ERR if ::arg was created from a
251 * different document than ::map,
252 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly,
253 * DOM_INUSE_ATTRIBUTE_ERR if ::arg is an Attr that is
254 * already an attribute on another
255 * Element,
256 * DOM_HIERARCHY_REQUEST_ERR if the type of ::arg is not
257 * permitted as a member of ::map.
258 * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
259 * feature "XML" and the language exposed
260 * through the Document does not support
261 * Namespaces.
262 *
263 * ::arg's namespaceURI and localName attributes will be used to store it in
264 * ::map. It will be accessible using the namespaceURI and localName
265 * attributes as the keys for lookup.
266 *
267 * Replacing a node by itself has no effect.
268 *
269 * The returned node will have had its reference count increased. The client
270 * should unref the node once it has finished with it.
271 */
_dom_namednodemap_set_named_item_ns(dom_namednodemap * map,dom_node * arg,dom_node ** node)272 dom_exception _dom_namednodemap_set_named_item_ns(
273 dom_namednodemap *map, dom_node *arg,
274 dom_node **node)
275 {
276 assert(map->opt != NULL);
277 return map->opt->namednodemap_set_named_item_ns(map->priv, arg, node);
278 }
279
280 /**
281 * Remove an item by namespace/localname from a named node map
282 *
283 * \param map The map to remove from
284 * \param namespace The namespace URI of the item to remove
285 * \param localname The local name of the item to remove
286 * \param node Pointer to location to receive removed item
287 * \return DOM_NO_ERR on success,
288 * DOM_NOT_FOUND_ERR if there is no node named ::name
289 * in ::map,
290 * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly.
291 * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
292 * feature "XML" and the language exposed
293 * through the Document does not support
294 * Namespaces.
295 *
296 * The returned node will have had its reference count increased. The client
297 * should unref the node once it has finished with it.
298 */
_dom_namednodemap_remove_named_item_ns(dom_namednodemap * map,dom_string * namespace,dom_string * localname,dom_node ** node)299 dom_exception _dom_namednodemap_remove_named_item_ns(
300 dom_namednodemap *map, dom_string *namespace,
301 dom_string *localname, dom_node **node)
302 {
303 assert(map->opt != NULL);
304 return map->opt->namednodemap_remove_named_item_ns(map->priv, namespace,
305 localname, node);
306 }
307
308 /**
309 * Compare whether two NamedNodeMap are equal.
310 *
311 */
_dom_namednodemap_equal(dom_namednodemap * m1,dom_namednodemap * m2)312 bool _dom_namednodemap_equal(dom_namednodemap *m1,
313 dom_namednodemap *m2)
314 {
315 assert(m1->opt != NULL);
316 return (m1->opt == m2->opt && m1->opt->namednodemap_equal(m1->priv,
317 m2->priv));
318 }
319
320 /**
321 * Update the dom_namednodemap to make it as a proxy of another object
322 *
323 * \param map The dom_namednodemap
324 * \param priv The private data to change to
325 */
_dom_namednodemap_update(dom_namednodemap * map,void * priv)326 void _dom_namednodemap_update(dom_namednodemap *map, void *priv)
327 {
328 map->priv = priv;
329 }
330