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