Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3584 sourcerer 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 
6
 * Copyright 2009 Bo Yang 
7
 */
8
 
9
#include 
10
#include 
11
 
12
typedef signed char int8_t;
13
typedef signed short int16_t;
14
typedef signed int int32_t;
15
 
16
typedef unsigned char uint8_t;
17
typedef unsigned short uint16_t;
18
typedef unsigned int uint32_t;
19
 
20
#include 
21
#include 
22
#include 
23
#include 
24
#include 
25
 
26
 
27
 
28
 
29
#include "core/string.h"
30
#include "core/attr.h"
31
#include "core/cdatasection.h"
32
#include "core/comment.h"
33
#include "core/document.h"
34
#include "core/doc_fragment.h"
35
#include "core/element.h"
36
#include "core/entity_ref.h"
37
#include "core/namednodemap.h"
38
#include "core/nodelist.h"
39
#include "core/pi.h"
40
#include "core/text.h"
41
#include "utils/validate.h"
42
#include "utils/namespace.h"
43
#include "utils/utils.h"
44
 
45
/**
46
 * Item in list of active nodelists
47
 */
48
struct dom_doc_nl {
49
	dom_nodelist *list;	/**< Nodelist */
50
 
51
	struct dom_doc_nl *next;	/**< Next item */
52
	struct dom_doc_nl *prev;	/**< Previous item */
53
};
54
 
55
/* The virtual functions of this dom_document */
56
static struct dom_document_vtable document_vtable = {
57
	{
58
		{
59
			DOM_NODE_EVENT_TARGET_VTABLE
60
		},
61
		DOM_NODE_VTABLE_DOCUMENT
62
	},
63
	DOM_DOCUMENT_VTABLE
64
};
65
 
66
static struct dom_node_protect_vtable document_protect_vtable = {
67
	DOM_DOCUMENT_PROTECT_VTABLE
68
};
69
 
70
 
71
/*----------------------------------------------------------------------*/
72
 
73
/* Internally used helper functions */
74
static dom_exception dom_document_dup_node(dom_document *doc,
75
		dom_node *node, bool deep, dom_node **result,
76
		dom_node_operation opt);
77
 
78
 
79
/*----------------------------------------------------------------------*/
80
 
81
/* The constructors and destructors */
82
 
83
/**
84
 * Create a Document
85
 *
86
 * \param doc    Pointer to location to receive created document
87
 * \param daf    The default action fetcher
88
 * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
89
 *
90
 * The returned document will already be referenced.
91
 */
92
dom_exception _dom_document_create(dom_events_default_action_fetcher daf,
93
				   void *daf_ctx,
94
				   dom_document **doc)
95
{
96
	dom_document *d;
97
	dom_exception err;
98
 
99
	/* Create document */
100
	d = malloc(sizeof(dom_document));
101
	if (d == NULL)
102
		return DOM_NO_MEM_ERR;
103
 
104
	/* Initialise the virtual table */
105
	d->base.base.vtable = &document_vtable;
106
	d->base.vtable = &document_protect_vtable;
107
 
108
	/* Initialise base class -- the Document has no parent, so
109
	 * destruction will be attempted as soon as its reference count
110
	 * reaches zero. Documents own themselves (this simplifies the
111
	 * rest of the code, as it doesn't need to special case Documents)
112
	 */
113
	err = _dom_document_initialise(d, daf, daf_ctx);
114
	if (err != DOM_NO_ERR) {
115
		/* Clean up document */
116
		free(d);
117
		return err;
118
	}
119
 
120
	*doc = d;
121
 
122
	return DOM_NO_ERR;
123
}
124
 
125
/* Initialise the document */
126
dom_exception _dom_document_initialise(dom_document *doc,
127
				       dom_events_default_action_fetcher daf,
128
				       void *daf_ctx)
129
{
130
	dom_exception err;
131
	dom_string *name;
132
 
133
	err = dom_string_create((const uint8_t *) "#document",
134
			SLEN("#document"), &name);
135
	if (err != DOM_NO_ERR)
136
		return err;
137
 
138
	doc->nodelists = NULL;
139
 
140
	err = _dom_node_initialise(&doc->base, doc, DOM_DOCUMENT_NODE,
141
			name, NULL, NULL, NULL);
142
	dom_string_unref(name);
143
        if (err != DOM_NO_ERR)
144
          return err;
145
 
146
	list_init(&doc->pending_nodes);
147
 
148
	err = dom_string_create_interned((const uint8_t *) "id",
149
					 SLEN("id"), &doc->id_name);
150
	if (err != DOM_NO_ERR)
151
		return err;
152
	doc->quirks = DOM_DOCUMENT_QUIRKS_MODE_NONE;
153
 
154
	err = dom_string_create_interned((const uint8_t *) "class",
155
			SLEN("class"), &doc->class_string);
156
	if (err != DOM_NO_ERR) {
157
		dom_string_unref(doc->id_name);
158
		return err;
159
	}
160
 
161
	/* Intern the empty string. The use of a space in the constant
162
	 * is to prevent the compiler warning about an empty string.
163
	 */
164
	err = dom_string_create_interned((const uint8_t *) " ", 0,
165
					 &doc->_memo_empty);
166
	if (err != DOM_NO_ERR) {
167
		dom_string_unref(doc->id_name);
168
		dom_string_unref(doc->class_string);
169
		return err;
170
	}
171
 
172
	err = dom_string_create_interned((const uint8_t *) "DOMNodeInserted",
173
					 SLEN("DOMNodeInserted"),
174
					 &doc->_memo_domnodeinserted);
175
	if (err != DOM_NO_ERR) {
176
		dom_string_unref(doc->_memo_empty);
177
		dom_string_unref(doc->id_name);
178
		dom_string_unref(doc->class_string);
179
		return err;
180
	}
181
 
182
	err = dom_string_create_interned((const uint8_t *) "DOMNodeRemoved",
183
					 SLEN("DOMNodeRemoved"),
184
					 &doc->_memo_domnoderemoved);
185
	if (err != DOM_NO_ERR) {
186
		dom_string_unref(doc->_memo_domnodeinserted);
187
		dom_string_unref(doc->_memo_empty);
188
		dom_string_unref(doc->id_name);
189
		dom_string_unref(doc->class_string);
190
		return err;
191
	}
192
 
193
	err = dom_string_create_interned((const uint8_t *) "DOMNodeInsertedIntoDocument",
194
					 SLEN("DOMNodeInsertedIntoDocument"),
195
					 &doc->_memo_domnodeinsertedintodocument);
196
	if (err != DOM_NO_ERR) {
197
		dom_string_unref(doc->_memo_domnoderemoved);
198
		dom_string_unref(doc->_memo_domnodeinserted);
199
		dom_string_unref(doc->_memo_empty);
200
		dom_string_unref(doc->id_name);
201
		dom_string_unref(doc->class_string);
202
		return err;
203
	}
204
 
205
	err = dom_string_create_interned((const uint8_t *) "DOMNodeRemovedFromDocument",
206
					 SLEN("DOMNodeRemovedFromDocument"),
207
					 &doc->_memo_domnoderemovedfromdocument);
208
	if (err != DOM_NO_ERR) {
209
		dom_string_unref(doc->_memo_domnodeinsertedintodocument);
210
		dom_string_unref(doc->_memo_domnoderemoved);
211
		dom_string_unref(doc->_memo_domnodeinserted);
212
		dom_string_unref(doc->_memo_empty);
213
		dom_string_unref(doc->id_name);
214
		dom_string_unref(doc->class_string);
215
		return err;
216
	}
217
 
218
	err = dom_string_create_interned((const uint8_t *) "DOMAttrModified",
219
					 SLEN("DOMAttrModified"),
220
					 &doc->_memo_domattrmodified);
221
	if (err != DOM_NO_ERR) {
222
		dom_string_unref(doc->_memo_domnoderemovedfromdocument);
223
		dom_string_unref(doc->_memo_domnodeinsertedintodocument);
224
		dom_string_unref(doc->_memo_domnoderemoved);
225
		dom_string_unref(doc->_memo_domnodeinserted);
226
		dom_string_unref(doc->_memo_empty);
227
		dom_string_unref(doc->id_name);
228
		dom_string_unref(doc->class_string);
229
		return err;
230
	}
231
 
232
	err = dom_string_create_interned((const uint8_t *) "DOMCharacterDataModified",
233
					 SLEN("DOMCharacterDataModified"),
234
					 &doc->_memo_domcharacterdatamodified);
235
	if (err != DOM_NO_ERR) {
236
		dom_string_unref(doc->_memo_domattrmodified);
237
		dom_string_unref(doc->_memo_domnoderemovedfromdocument);
238
		dom_string_unref(doc->_memo_domnodeinsertedintodocument);
239
		dom_string_unref(doc->_memo_domnoderemoved);
240
		dom_string_unref(doc->_memo_domnodeinserted);
241
		dom_string_unref(doc->_memo_empty);
242
		dom_string_unref(doc->id_name);
243
		dom_string_unref(doc->class_string);
244
		return err;
245
	}
246
 
247
	err = dom_string_create_interned((const uint8_t *) "DOMSubtreeModified",
248
					 SLEN("DOMSubtreeModified"),
249
					 &doc->_memo_domsubtreemodified);
250
	if (err != DOM_NO_ERR) {
251
		dom_string_unref(doc->_memo_domcharacterdatamodified);
252
		dom_string_unref(doc->_memo_domattrmodified);
253
		dom_string_unref(doc->_memo_domnoderemovedfromdocument);
254
		dom_string_unref(doc->_memo_domnodeinsertedintodocument);
255
		dom_string_unref(doc->_memo_domnoderemoved);
256
		dom_string_unref(doc->_memo_domnodeinserted);
257
		dom_string_unref(doc->_memo_empty);
258
		dom_string_unref(doc->id_name);
259
		dom_string_unref(doc->class_string);
260
		return err;
261
	}
262
 
263
	/* We should not pass a NULL when all things hook up */
264
	return _dom_document_event_internal_initialise(doc, &doc->dei, daf, daf_ctx);
265
}
266
 
267
 
268
/* Finalise the document */
269
bool _dom_document_finalise(dom_document *doc)
270
{
271
	/* Finalise base class, delete the tree in force */
272
	_dom_node_finalise(&doc->base);
273
 
274
	/* Now, the first_child and last_child should be null */
275
	doc->base.first_child = NULL;
276
	doc->base.last_child = NULL;
277
 
278
	/* Ensure list of nodes pending deletion is empty. If not,
279
	 * then we can't yet destroy the document (its destruction will
280
	 * have to wait until the pending nodes are destroyed) */
281
	if (doc->pending_nodes.next != &doc->pending_nodes)
282
		return false;
283
 
284
	/* Ok, the document tree is empty, as is the list of nodes pending
285
	 * deletion. Therefore, it is safe to destroy the document. */
286
 
287
	/* This is paranoia -- if there are any remaining nodelists,
288
	 * then the document's reference count will be
289
	 * non-zero as these data structures reference the document because
290
	 * they are held by the client. */
291
	doc->nodelists = NULL;
292
 
293
	if (doc->id_name != NULL)
294
		dom_string_unref(doc->id_name);
295
 
296
	dom_string_unref(doc->class_string);
297
	dom_string_unref(doc->_memo_empty);
298
	dom_string_unref(doc->_memo_domnodeinserted);
299
	dom_string_unref(doc->_memo_domnoderemoved);
300
	dom_string_unref(doc->_memo_domnodeinsertedintodocument);
301
	dom_string_unref(doc->_memo_domnoderemovedfromdocument);
302
	dom_string_unref(doc->_memo_domattrmodified);
303
	dom_string_unref(doc->_memo_domcharacterdatamodified);
304
	dom_string_unref(doc->_memo_domsubtreemodified);
305
 
306
	_dom_document_event_internal_finalise(doc, &doc->dei);
307
 
308
	return true;
309
}
310
 
311
 
312
 
313
/*----------------------------------------------------------------------*/
314
 
315
/* Public virtual functions */
316
 
317
/**
318
 * Retrieve the doctype of a document
319
 *
320
 * \param doc     The document to retrieve the doctype from
321
 * \param result  Pointer to location to receive result
322
 * \return DOM_NO_ERR.
323
 *
324
 * The returned node will have its reference count increased. It is
325
 * the responsibility of the caller to unref the node once it has
326
 * finished with it.
327
 */
328
dom_exception _dom_document_get_doctype(dom_document *doc,
329
		dom_document_type **result)
330
{
331
	dom_node_internal *c;
332
 
333
	for (c = doc->base.first_child; c != NULL; c = c->next) {
334
		if (c->type == DOM_DOCUMENT_TYPE_NODE)
335
			break;
336
	}
337
 
338
	if (c != NULL)
339
		dom_node_ref(c);
340
 
341
	*result = (dom_document_type *) c;
342
 
343
	return DOM_NO_ERR;
344
}
345
 
346
/**
347
 * Retrieve the DOM implementation that handles this document
348
 *
349
 * \param doc     The document to retrieve the implementation from
350
 * \param result  Pointer to location to receive result
351
 * \return DOM_NO_ERR.
352
 *
353
 * The returned implementation will have its reference count increased.
354
 * It is the responsibility of the caller to unref the implementation once
355
 * it has finished with it.
356
 */
357
dom_exception _dom_document_get_implementation(dom_document *doc,
358
		dom_implementation **result)
359
{
360
	UNUSED(doc);
361
 
362
	*result = (dom_implementation *) "libdom";
363
 
364
	return DOM_NO_ERR;
365
}
366
 
367
/**
368
 * Retrieve the document element of a document
369
 *
370
 * \param doc     The document to retrieve the document element from
371
 * \param result  Pointer to location to receive result
372
 * \return DOM_NO_ERR.
373
 *
374
 * The returned node will have its reference count increased. It is
375
 * the responsibility of the caller to unref the node once it has
376
 * finished with it.
377
 */
378
dom_exception _dom_document_get_document_element(dom_document *doc,
379
		dom_element **result)
380
{
381
	dom_node_internal *root;
382
 
383
	/* Find the first element node in child list */
384
	for (root = doc->base.first_child; root != NULL; root = root->next) {
385
		if (root->type == DOM_ELEMENT_NODE)
386
			break;
387
	}
388
 
389
	if (root != NULL)
390
		dom_node_ref(root);
391
 
392
	*result = (dom_element *) root;
393
 
394
	return DOM_NO_ERR;
395
}
396
 
397
/**
398
 * Create an element
399
 *
400
 * \param doc       The document owning the element
401
 * \param tag_name  The name of the element
402
 * \param result    Pointer to location to receive result
403
 * \return DOM_NO_ERR                on success,
404
 *         DOM_INVALID_CHARACTER_ERR if ::tag_name is invalid.
405
 *
406
 * ::doc and ::tag_name will have their reference counts increased.
407
 *
408
 * The returned node will have its reference count increased. It is
409
 * the responsibility of the caller to unref the node once it has
410
 * finished with it.
411
 */
412
dom_exception _dom_document_create_element(dom_document *doc,
413
		dom_string *tag_name, dom_element **result)
414
{
415
	if (_dom_validate_name(tag_name) == false)
416
		return DOM_INVALID_CHARACTER_ERR;
417
 
418
	return _dom_element_create(doc, tag_name, NULL, NULL, result);
419
}
420
 
421
/**
422
 * Create a document fragment
423
 *
424
 * \param doc     The document owning the fragment
425
 * \param result  Pointer to location to receive result
426
 * \return DOM_NO_ERR.
427
 *
428
 * The returned node will have its reference count increased. It is
429
 * the responsibility of the caller to unref the node once it has
430
 * finished with it.
431
 */
432
dom_exception _dom_document_create_document_fragment(dom_document *doc,
433
		dom_document_fragment **result)
434
{
435
	dom_string *name;
436
	dom_exception err;
437
 
438
	err = dom_string_create((const uint8_t *) "#document-fragment",
439
			SLEN("#document-fragment"), &name);
440
	if (err != DOM_NO_ERR)
441
		return err;
442
 
443
	err = _dom_document_fragment_create(doc, name, NULL, result);
444
	dom_string_unref(name);
445
 
446
	return err;
447
}
448
 
449
/**
450
 * Create a text node
451
 *
452
 * \param doc     The document owning the node
453
 * \param data    The data for the node
454
 * \param result  Pointer to location to receive result
455
 * \return DOM_NO_ERR.
456
 *
457
 * The returned node will have its reference count increased. It is
458
 * the responsibility of the caller to unref the node once it has
459
 * finished with it.
460
 */
461
dom_exception _dom_document_create_text_node(dom_document *doc,
462
		dom_string *data, dom_text **result)
463
{
464
	dom_string *name;
465
	dom_exception err;
466
 
467
	err = dom_string_create((const uint8_t *) "#text",
468
			SLEN("#text"), &name);
469
	if (err != DOM_NO_ERR)
470
		return err;
471
 
472
	err = _dom_text_create(doc, name, data, result);
473
	dom_string_unref(name);
474
 
475
	return err;
476
}
477
 
478
/**
479
 * Create a comment node
480
 *
481
 * \param doc     The document owning the node
482
 * \param data    The data for the node
483
 * \param result  Pointer to location to receive result
484
 * \return DOM_NO_ERR.
485
 *
486
 * The returned node will have its reference count increased. It is
487
 * the responsibility of the caller to unref the node once it has
488
 * finished with it.
489
 */
490
dom_exception _dom_document_create_comment(dom_document *doc,
491
		dom_string *data, dom_comment **result)
492
{
493
	dom_string *name;
494
	dom_exception err;
495
 
496
	err = dom_string_create((const uint8_t *) "#comment", SLEN("#comment"),
497
			&name);
498
	if (err != DOM_NO_ERR)
499
		return err;
500
 
501
	err = _dom_comment_create(doc, name, data, result);
502
	dom_string_unref(name);
503
 
504
	return err;
505
}
506
 
507
/**
508
 * Create a CDATA section
509
 *
510
 * \param doc     The document owning the section
511
 * \param data    The data for the section contents
512
 * \param result  Pointer to location to receive result
513
 * \return DOM_NO_ERR            on success,
514
 *         DOM_NOT_SUPPORTED_ERR if this is an HTML document.
515
 *
516
 * The returned node will have its reference count increased. It is
517
 * the responsibility of the caller to unref the node once it has
518
 * finished with it.
519
 */
520
dom_exception _dom_document_create_cdata_section(dom_document *doc,
521
		dom_string *data, dom_cdata_section **result)
522
{
523
	dom_string *name;
524
	dom_exception err;
525
 
526
	err = dom_string_create((const uint8_t *) "#cdata-section",
527
			SLEN("#cdata-section"), &name);
528
	if (err != DOM_NO_ERR)
529
		return err;
530
 
531
	err = _dom_cdata_section_create(doc, name, data, result);
532
	dom_string_unref(name);
533
 
534
	return err;
535
}
536
 
537
/**
538
 * Create a processing instruction
539
 *
540
 * \param doc     The document owning the instruction
541
 * \param target  The instruction target
542
 * \param data    The data for the node
543
 * \param result  Pointer to location to receive result
544
 * \return DOM_NO_ERR                on success,
545
 *         DOM_INVALID_CHARACTER_ERR if ::target is invalid,
546
 *         DOM_NOT_SUPPORTED_ERR     if this is an HTML document.
547
 *
548
 * The returned node will have its reference count increased. It is
549
 * the responsibility of the caller to unref the node once it has
550
 * finished with it.
551
 */
552
dom_exception _dom_document_create_processing_instruction(
553
		dom_document *doc, dom_string *target,
554
		dom_string *data,
555
		dom_processing_instruction **result)
556
{
557
	if (_dom_validate_name(target) == false)
558
		return DOM_INVALID_CHARACTER_ERR;
559
 
560
	return _dom_processing_instruction_create(doc, target, data, result);
561
}
562
 
563
/**
564
 * Create an attribute
565
 *
566
 * \param doc     The document owning the attribute
567
 * \param name    The name of the attribute
568
 * \param result  Pointer to location to receive result
569
 * \return DOM_NO_ERR                on success,
570
 *         DOM_INVALID_CHARACTER_ERR if ::name is invalid.
571
 *
572
 * The constructed attribute will always be classified as 'specified'.
573
 *
574
 * The returned node will have its reference count increased. It is
575
 * the responsibility of the caller to unref the node once it has
576
 * finished with it.
577
 */
578
dom_exception _dom_document_create_attribute(dom_document *doc,
579
		dom_string *name, dom_attr **result)
580
{
581
	if (_dom_validate_name(name) == false)
582
		return DOM_INVALID_CHARACTER_ERR;
583
 
584
	return _dom_attr_create(doc, name, NULL, NULL, true, result);
585
}
586
 
587
/**
588
 * Create an entity reference
589
 *
590
 * \param doc     The document owning the reference
591
 * \param name    The name of the entity to reference
592
 * \param result  Pointer to location to receive result
593
 * \return DOM_NO_ERR                on success,
594
 *         DOM_INVALID_CHARACTER_ERR if ::name is invalid,
595
 *         DOM_NOT_SUPPORTED_ERR     if this is an HTML document.
596
 *
597
 * The returned node will have its reference count increased. It is
598
 * the responsibility of the caller to unref the node once it has
599
 * finished with it.
600
 */
601
dom_exception _dom_document_create_entity_reference(dom_document *doc,
602
		dom_string *name,
603
		dom_entity_reference **result)
604
{
605
	if (_dom_validate_name(name) == false)
606
		return DOM_INVALID_CHARACTER_ERR;
607
 
608
	return _dom_entity_reference_create(doc, name, NULL, result);
609
}
610
 
611
/**
612
 * Retrieve a list of all elements with a given tag name
613
 *
614
 * \param doc      The document to search in
615
 * \param tagname  The tag name to search for ("*" for all)
616
 * \param result   Pointer to location to receive result
617
 * \return DOM_NO_ERR.
618
 *
619
 * The returned list will have its reference count increased. It is
620
 * the responsibility of the caller to unref the list once it has
621
 * finished with it.
622
 */
623
dom_exception _dom_document_get_elements_by_tag_name(dom_document *doc,
624
		dom_string *tagname, dom_nodelist **result)
625
{
626
	return _dom_document_get_nodelist(doc, DOM_NODELIST_BY_NAME,
627
			(dom_node_internal *) doc,  tagname, NULL, NULL,
628
			result);
629
}
630
 
631
/**
632
 * Import a node from another document into this one
633
 *
634
 * \param doc     The document to import into
635
 * \param node    The node to import
636
 * \param deep    Whether to copy the node's subtree
637
 * \param result  Pointer to location to receive imported node in this document.
638
 * \return DOM_NO_ERR                on success,
639
 *         DOM_INVALID_CHARACTER_ERR if any of the names are invalid,
640
 *         DOM_NOT_SUPPORTED_ERR     if the type of ::node is unsupported
641
 *
642
 * The returned node will have its reference count increased. It is
643
 * the responsibility of the caller to unref the node once it has
644
 * finished with it.
645
 */
646
dom_exception _dom_document_import_node(dom_document *doc,
647
		dom_node *node, bool deep, dom_node **result)
648
{
649
	/* TODO: The DOM_INVALID_CHARACTER_ERR exception */
650
 
651
	return dom_document_dup_node(doc, node, deep, result,
652
			DOM_NODE_IMPORTED);
653
}
654
 
655
/**
656
 * Create an element from the qualified name and namespace URI
657
 *
658
 * \param doc        The document owning the element
659
 * \param namespace  The namespace URI to use, or NULL for none
660
 * \param qname      The qualified name of the element
661
 * \param result     Pointer to location to receive result
662
 * \return DOM_NO_ERR                on success,
663
 *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
664
 *         DOM_NAMESPACE_ERR         if ::qname is malformed, or it has a
665
 *                                   prefix and ::namespace is NULL, or
666
 *                                   ::qname has a prefix "xml" and
667
 *                                   ::namespace is not
668
 *                                   "http://www.w3.org/XML/1998/namespace",
669
 *                                   or ::qname has a prefix "xmlns" and
670
 *                                   ::namespace is not
671
 *                                   "http://www.w3.org/2000/xmlns", or
672
 *                                   ::namespace is
673
 *                                   "http://www.w3.org/2000/xmlns" and
674
 *                                   ::qname is not (or is not prefixed by)
675
 *                                   "xmlns",
676
 *         DOM_NOT_SUPPORTED_ERR     if ::doc does not support the "XML"
677
 *                                   feature.
678
 *
679
 * The returned node will have its reference count increased. It is
680
 * the responsibility of the caller to unref the node once it has
681
 * finished with it.
682
 */
683
dom_exception _dom_document_create_element_ns(dom_document *doc,
684
		dom_string *namespace, dom_string *qname,
685
		dom_element **result)
686
{
687
	dom_string *prefix, *localname;
688
	dom_exception err;
689
 
690
	if (_dom_validate_name(qname) == false)
691
		return DOM_INVALID_CHARACTER_ERR;
692
 
693
	/* Validate qname */
694
	err = _dom_namespace_validate_qname(qname, namespace);
695
	if (err != DOM_NO_ERR) {
696
		return err;
697
	}
698
 
699
	/* Divide QName into prefix/localname pair */
700
	err = _dom_namespace_split_qname(qname, &prefix, &localname);
701
	if (err != DOM_NO_ERR) {
702
		return err;
703
	}
704
 
705
	/* Attempt to create element */
706
	err = _dom_element_create(doc, localname, namespace, prefix, result);
707
 
708
	/* Tidy up */
709
	if (localname != NULL) {
710
		dom_string_unref(localname);
711
	}
712
 
713
	if (prefix != NULL) {
714
		dom_string_unref(prefix);
715
	}
716
 
717
	return err;
718
}
719
 
720
/**
721
 * Create an attribute from the qualified name and namespace URI
722
 *
723
 * \param doc        The document owning the attribute
724
 * \param namespace  The namespace URI to use
725
 * \param qname      The qualified name of the attribute
726
 * \param result     Pointer to location to receive result
727
 * \return DOM_NO_ERR                on success,
728
 *         DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
729
 *         DOM_NAMESPACE_ERR         if ::qname is malformed, or it has a
730
 *                                   prefix and ::namespace is NULL, or
731
 *                                   ::qname has a prefix "xml" and
732
 *                                   ::namespace is not
733
 *                                   "http://www.w3.org/XML/1998/namespace",
734
 *                                   or ::qname has a prefix "xmlns" and
735
 *                                   ::namespace is not
736
 *                                   "http://www.w3.org/2000/xmlns", or
737
 *                                   ::namespace is
738
 *                                   "http://www.w3.org/2000/xmlns" and
739
 *                                   ::qname is not (or is not prefixed by)
740
 *                                   "xmlns",
741
 *         DOM_NOT_SUPPORTED_ERR     if ::doc does not support the "XML"
742
 *                                   feature.
743
 *
744
 * The returned node will have its reference count increased. It is
745
 * the responsibility of the caller to unref the node once it has
746
 * finished with it.
747
 */
748
dom_exception _dom_document_create_attribute_ns(dom_document *doc,
749
		dom_string *namespace, dom_string *qname,
750
		dom_attr **result)
751
{
752
	dom_string *prefix, *localname;
753
	dom_exception err;
754
 
755
	if (_dom_validate_name(qname) == false)
756
		return DOM_INVALID_CHARACTER_ERR;
757
 
758
	/* Validate qname */
759
	err = _dom_namespace_validate_qname(qname, namespace);
760
	if (err != DOM_NO_ERR) {
761
		return err;
762
	}
763
 
764
	/* Divide QName into prefix/localname pair */
765
	err = _dom_namespace_split_qname(qname, &prefix, &localname);
766
	if (err != DOM_NO_ERR) {
767
		return err;
768
	}
769
 
770
	/* Attempt to create attribute */
771
	err = _dom_attr_create(doc, localname, namespace, prefix, true, result);
772
 
773
	/* Tidy up */
774
	if (localname != NULL) {
775
		dom_string_unref(localname);
776
	}
777
 
778
	if (prefix != NULL) {
779
		dom_string_unref(prefix);
780
	}
781
 
782
	return err;
783
}
784
 
785
/**
786
 * Retrieve a list of all elements with a given local name and namespace URI
787
 *
788
 * \param doc        The document to search in
789
 * \param namespace  The namespace URI
790
 * \param localname  The local name
791
 * \param result     Pointer to location to receive result
792
 * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
793
 *
794
 * The returned list will have its reference count increased. It is
795
 * the responsibility of the caller to unref the list once it has
796
 * finished with it.
797
 */
798
dom_exception _dom_document_get_elements_by_tag_name_ns(
799
		dom_document *doc, dom_string *namespace,
800
		dom_string *localname, dom_nodelist **result)
801
{
802
	return _dom_document_get_nodelist(doc, DOM_NODELIST_BY_NAMESPACE,
803
			(dom_node_internal *) doc, NULL, namespace, localname,
804
			result);
805
}
806
 
807
/**
808
 * Retrieve the element that matches the specified ID
809
 *
810
 * \param doc     The document to search in
811
 * \param id      The ID to search for
812
 * \param result  Pointer to location to receive result
813
 * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
814
 *
815
 * The returned node will have its reference count increased. It is
816
 * the responsibility of the caller to unref the node once it has
817
 * finished with it.
818
 */
819
dom_exception _dom_document_get_element_by_id(dom_document *doc,
820
		dom_string *id, dom_element **result)
821
{
822
	dom_node_internal *root;
823
	dom_exception err;
824
 
825
	*result = NULL;
826
 
827
	err = dom_document_get_document_element(doc, (void *) &root);
828
	if (err != DOM_NO_ERR)
829
		return err;
830
 
831
	err = _dom_find_element_by_id(root, id, result);
832
	dom_node_unref(root);
833
 
834
	return err;
835
}
836
 
837
/**
838
 * Retrieve the input encoding of the document
839
 *
840
 * \param doc     The document to query
841
 * \param result  Pointer to location to receive result
842
 * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
843
 *
844
 * The returned string will have its reference count increased. It is
845
 * the responsibility of the caller to unref the string once it has
846
 * finished with it.
847
 */
848
dom_exception _dom_document_get_input_encoding(dom_document *doc,
849
		dom_string **result)
850
{
851
	UNUSED(doc);
852
	UNUSED(result);
853
 
854
	return DOM_NOT_SUPPORTED_ERR;
855
}
856
 
857
/**
858
 * Retrieve the XML encoding of the document
859
 *
860
 * \param doc     The document to query
861
 * \param result  Pointer to location to receive result
862
 * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
863
 *
864
 * The returned string will have its reference count increased. It is
865
 * the responsibility of the caller to unref the string once it has
866
 * finished with it.
867
 */
868
dom_exception _dom_document_get_xml_encoding(dom_document *doc,
869
		dom_string **result)
870
{
871
	UNUSED(doc);
872
	UNUSED(result);
873
 
874
	return DOM_NOT_SUPPORTED_ERR;
875
}
876
 
877
/**
878
 * Retrieve the standalone status of the document
879
 *
880
 * \param doc     The document to query
881
 * \param result  Pointer to location to receive result
882
 * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
883
 */
884
dom_exception _dom_document_get_xml_standalone(dom_document *doc,
885
		bool *result)
886
{
887
	UNUSED(doc);
888
	UNUSED(result);
889
 
890
	return DOM_NOT_SUPPORTED_ERR;
891
}
892
 
893
/**
894
 * Set the standalone status of the document
895
 *
896
 * \param doc         The document to query
897
 * \param standalone  Standalone status to use
898
 * \return DOM_NO_ERR            on success,
899
 *         DOM_NOT_SUPPORTED_ERR if the document does not support the "XML"
900
 *                               feature.
901
 *
902
 * We don't support this API now, so the return value is always
903
 * DOM_NOT_SUPPORTED_ERR.
904
 */
905
dom_exception _dom_document_set_xml_standalone(dom_document *doc,
906
		bool standalone)
907
{
908
	UNUSED(doc);
909
	UNUSED(standalone);
910
 
911
	return DOM_NOT_SUPPORTED_ERR;
912
}
913
 
914
/**
915
 * Retrieve the XML version of the document
916
 *
917
 * \param doc     The document to query
918
 * \param result  Pointer to location to receive result
919
 * \return DOM_NO_ERR
920
 *
921
 * The returned string will have its reference count increased. It is
922
 * the responsibility of the caller to unref the string once it has
923
 * finished with it.
924
 *
925
 * We don't support this API now, so the return value is always
926
 * DOM_NOT_SUPPORTED_ERR.
927
 */
928
dom_exception _dom_document_get_xml_version(dom_document *doc,
929
		dom_string **result)
930
{
931
	UNUSED(doc);
932
	UNUSED(result);
933
 
934
	return DOM_NOT_SUPPORTED_ERR;
935
}
936
 
937
/**
938
 * Set the XML version of the document
939
 *
940
 * \param doc      The document to query
941
 * \param version  XML version to use
942
 * \return DOM_NO_ERR            on success,
943
 *         DOM_NOT_SUPPORTED_ERR if the document does not support the "XML"
944
 *                               feature.
945
 *
946
 * We don't support this API now, so the return value is always
947
 * DOM_NOT_SUPPORTED_ERR.
948
 */
949
dom_exception _dom_document_set_xml_version(dom_document *doc,
950
		dom_string *version)
951
{
952
	UNUSED(doc);
953
	UNUSED(version);
954
 
955
	return DOM_NOT_SUPPORTED_ERR;
956
}
957
 
958
/**
959
 * Retrieve the error checking mode of the document
960
 *
961
 * \param doc     The document to query
962
 * \param result  Pointer to location to receive result
963
 * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
964
 */
965
dom_exception _dom_document_get_strict_error_checking(
966
		dom_document *doc, bool *result)
967
{
968
	UNUSED(doc);
969
	UNUSED(result);
970
 
971
	return DOM_NOT_SUPPORTED_ERR;
972
}
973
 
974
/**
975
 * Set the error checking mode of the document
976
 *
977
 * \param doc     The document to query
978
 * \param strict  Whether to use strict error checking
979
 * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
980
 */
981
dom_exception _dom_document_set_strict_error_checking(
982
		dom_document *doc, bool strict)
983
{
984
	UNUSED(doc);
985
	UNUSED(strict);
986
 
987
	return DOM_NOT_SUPPORTED_ERR;
988
}
989
 
990
/**
991
 * Retrieve the URI of the document
992
 *
993
 * \param doc     The document to query
994
 * \param result  Pointer to location to receive result
995
 * \return DOM_NO_ERR.
996
 *
997
 * The returned string will have its reference count increased. It is
998
 * the responsibility of the caller to unref the string once it has
999
 * finished with it.
1000
 */
1001
dom_exception _dom_document_get_uri(dom_document *doc,
1002
		dom_string **result)
1003
{
1004
	*result = dom_string_ref(doc->uri);
1005
 
1006
	return DOM_NO_ERR;
1007
}
1008
 
1009
/**
1010
 * Set the URI of the document
1011
 *
1012
 * \param doc  The document to query
1013
 * \param uri  The URI to use
1014
 * \return DOM_NO_ERR.
1015
 *
1016
 * The returned string will have its reference count increased. It is
1017
 * the responsibility of the caller to unref the string once it has
1018
 * finished with it.
1019
 */
1020
dom_exception _dom_document_set_uri(dom_document *doc,
1021
		dom_string *uri)
1022
{
1023
	dom_string_unref(doc->uri);
1024
 
1025
	doc->uri = dom_string_ref(uri);
1026
 
1027
	return DOM_NO_ERR;
1028
}
1029
 
1030
/**
1031
 * Attempt to adopt a node from another document into this document
1032
 *
1033
 * \param doc     The document to adopt into
1034
 * \param node    The node to adopt
1035
 * \param result  Pointer to location to receive adopted node
1036
 * \return DOM_NO_ERR                      on success,
1037
 *         DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly,
1038
 *         DOM_NOT_SUPPORTED_ERR           if ::node is of type Document or
1039
 *                                         DocumentType
1040
 *
1041
 * The returned node will have its reference count increased. It is
1042
 * the responsibility of the caller to unref the node once it has
1043
 * finished with it.
1044
 *
1045
 * @note: The spec said adoptNode may be light weight than the importNode
1046
 *	  because the former need no Node creation. But in our implementation
1047
 *	  this can't be ensured. Both adoptNode and importNode create new
1048
 *	  nodes using the importing/adopting document's resource manager. So,
1049
 *	  generally, the adoptNode and importNode call the same function
1050
 *	  dom_document_dup_node.
1051
 */
1052
dom_exception _dom_document_adopt_node(dom_document *doc,
1053
		dom_node *node, dom_node **result)
1054
{
1055
	dom_node_internal *n = (dom_node_internal *) node;
1056
	dom_exception err;
1057
	dom_node_internal *parent;
1058
	dom_node_internal *tmp;
1059
 
1060
	*result = NULL;
1061
 
1062
	if (n->type == DOM_DOCUMENT_NODE ||
1063
			n->type == DOM_DOCUMENT_TYPE_NODE) {
1064
		return DOM_NOT_SUPPORTED_ERR;
1065
	}
1066
 
1067
	if (n->type == DOM_ENTITY_NODE ||
1068
			n->type == DOM_NOTATION_NODE ||
1069
			n->type == DOM_PROCESSING_INSTRUCTION_NODE ||
1070
			n->type == DOM_TEXT_NODE ||
1071
			n->type == DOM_CDATA_SECTION_NODE ||
1072
			n->type == DOM_COMMENT_NODE) {
1073
		*result = NULL;
1074
		return DOM_NO_ERR;
1075
	}
1076
 
1077
	/* Support XML when necessary */
1078
	if (n->type == DOM_ENTITY_REFERENCE_NODE) {
1079
		return DOM_NOT_SUPPORTED_ERR;
1080
	}
1081
 
1082
	err = dom_document_dup_node(doc, node, true, result, DOM_NODE_ADOPTED);
1083
	if (err != DOM_NO_ERR) {
1084
		*result = NULL;
1085
		return err;
1086
	}
1087
 
1088
	parent = n->parent;
1089
	if (parent != NULL) {
1090
		err = dom_node_remove_child(parent, node, (void *) &tmp);
1091
		if (err != DOM_NO_ERR) {
1092
			dom_node_unref(*result);
1093
			*result = NULL;
1094
			return err;
1095
		}
1096
                dom_node_unref(tmp);
1097
	}
1098
 
1099
	return DOM_NO_ERR;
1100
}
1101
 
1102
/**
1103
 * Retrieve the DOM configuration associated with a document
1104
 *
1105
 * \param doc     The document to query
1106
 * \param result  Pointer to location to receive result
1107
 * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
1108
 *
1109
 * The returned object will have its reference count increased. It is
1110
 * the responsibility of the caller to unref the object once it has
1111
 * finished with it.
1112
 */
1113
dom_exception _dom_document_get_dom_config(dom_document *doc,
1114
		struct dom_configuration **result)
1115
{
1116
	UNUSED(doc);
1117
	UNUSED(result);
1118
 
1119
	return DOM_NOT_SUPPORTED_ERR;
1120
}
1121
 
1122
/**
1123
 * Normalize a document
1124
 *
1125
 * \param doc  The document to normalize
1126
 * \return DOM_NOT_SUPPORTED_ERR, we don't support this API now.
1127
 */
1128
dom_exception _dom_document_normalize(dom_document *doc)
1129
{
1130
	UNUSED(doc);
1131
 
1132
	return DOM_NOT_SUPPORTED_ERR;
1133
}
1134
 
1135
/**
1136
 * Rename a node in a document
1137
 *
1138
 * \param doc        The document containing the node
1139
 * \param node       The node to rename
1140
 * \param namespace  The new namespace for the node
1141
 * \param qname      The new qualified name for the node
1142
 * \param result     Pointer to location to receive renamed node
1143
 * \return DOM_NO_ERR                on success,
1144
 *         DOM_INVALID_CHARACTER_ERR if ::tag_name is invalid,
1145
 *         DOM_WRONG_DOCUMENT_ERR    if ::node was created in a different
1146
 *                                   document
1147
 *         DOM_NAMESPACE_ERR         if ::qname is malformed, or it has a
1148
 *                                   prefix and ::namespace is NULL, or
1149
 *                                   ::qname has a prefix "xml" and
1150
 *                                   ::namespace is not
1151
 *                                   "http://www.w3.org/XML/1998/namespace",
1152
 *                                   or ::qname has a prefix "xmlns" and
1153
 *                                   ::namespace is not
1154
 *                                   "http://www.w3.org/2000/xmlns", or
1155
 *                                   ::namespace is
1156
 *                                   "http://www.w3.org/2000/xmlns" and
1157
 *                                   ::qname is not (or is not prefixed by)
1158
 *                                   "xmlns",
1159
 *         DOM_NOT_SUPPORTED_ERR     if ::doc does not support the "XML"
1160
 *                                   feature.
1161
 *
1162
 * The returned node will have its reference count increased. It is
1163
 * the responsibility of the caller to unref the node once it has
1164
 * finished with it.
1165
 *
1166
 * We don't support this API now, so the return value is always
1167
 * DOM_NOT_SUPPORTED_ERR.
1168
 */
1169
dom_exception _dom_document_rename_node(dom_document *doc,
1170
		dom_node *node,
1171
		dom_string *namespace, dom_string *qname,
1172
		dom_node **result)
1173
{
1174
	UNUSED(doc);
1175
	UNUSED(node);
1176
	UNUSED(namespace);
1177
	UNUSED(qname);
1178
	UNUSED(result);
1179
 
1180
	return DOM_NOT_SUPPORTED_ERR;
1181
}
1182
 
1183
dom_exception _dom_document_get_text_content(dom_node_internal *node,
1184
					     dom_string **result)
1185
{
1186
	UNUSED(node);
1187
 
1188
	*result = NULL;
1189
 
1190
	return DOM_NO_ERR;
1191
}
1192
 
1193
dom_exception _dom_document_set_text_content(dom_node_internal *node,
1194
					     dom_string *content)
1195
{
1196
	UNUSED(node);
1197
	UNUSED(content);
1198
 
1199
	return DOM_NO_ERR;
1200
}
1201
 
1202
/*-----------------------------------------------------------------------*/
1203
 
1204
/* Overload protected virtual functions */
1205
 
1206
/* The virtual destroy function of this class */
1207
void _dom_document_destroy(dom_node_internal *node)
1208
{
1209
	dom_document *doc = (dom_document *) node;
1210
 
1211
	if (_dom_document_finalise(doc) == true) {
1212
		free(doc);
1213
	}
1214
}
1215
 
1216
/* The copy constructor function of this class */
1217
dom_exception _dom_document_copy(dom_node_internal *old,
1218
		dom_node_internal **copy)
1219
{
1220
	UNUSED(old);
1221
	UNUSED(copy);
1222
 
1223
	return DOM_NOT_SUPPORTED_ERR;
1224
}
1225
 
1226
 
1227
/* ----------------------------------------------------------------------- */
1228
 
1229
/* Helper functions */
1230
 
1231
/**
1232
 * Get a nodelist, creating one if necessary
1233
 *
1234
 * \param doc        The document to get a nodelist for
1235
 * \param type	     The type of the NodeList
1236
 * \param root       Root node of subtree that list applies to
1237
 * \param tagname    Name of nodes in list (or NULL)
1238
 * \param namespace  Namespace part of nodes in list (or NULL)
1239
 * \param localname  Local part of nodes in list (or NULL)
1240
 * \param list       Pointer to location to receive list
1241
 * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
1242
 *
1243
 * The returned list will have its reference count increased. It is
1244
 * the responsibility of the caller to unref the list once it has
1245
 * finished with it.
1246
 */
1247
dom_exception _dom_document_get_nodelist(dom_document *doc,
1248
		nodelist_type type, dom_node_internal *root,
1249
		dom_string *tagname, dom_string *namespace,
1250
		dom_string *localname, dom_nodelist **list)
1251
{
1252
	struct dom_doc_nl *l;
1253
	dom_exception err;
1254
 
1255
	for (l = doc->nodelists; l; l = l->next) {
1256
		if (_dom_nodelist_match(l->list, type, root, tagname,
1257
				namespace, localname))
1258
			break;
1259
	}
1260
 
1261
	if (l != NULL) {
1262
		/* Found an existing list, so use it */
1263
		dom_nodelist_ref(l->list);
1264
	} else {
1265
		/* No existing list */
1266
 
1267
		/* Create active list entry */
1268
		l = malloc(sizeof(struct dom_doc_nl));
1269
		if (l == NULL)
1270
			return DOM_NO_MEM_ERR;
1271
 
1272
		/* Create nodelist */
1273
		err = _dom_nodelist_create(doc, type, root, tagname, namespace,
1274
				localname, &l->list);
1275
		if (err != DOM_NO_ERR) {
1276
			free(l);
1277
			return err;
1278
		}
1279
 
1280
		/* Add to document's list of active nodelists */
1281
		l->prev = NULL;
1282
		l->next = doc->nodelists;
1283
		if (doc->nodelists)
1284
			doc->nodelists->prev = l;
1285
		doc->nodelists = l;
1286
	}
1287
 
1288
	/* Note: the document does not claim a reference on the nodelist
1289
	 * If it did, the nodelist's reference count would never reach zero,
1290
	 * and the list would remain indefinitely. This is not a problem as
1291
	 * the list notifies the document of its destruction via
1292
	 * _dom_document_remove_nodelist. */
1293
 
1294
	*list = l->list;
1295
 
1296
	return DOM_NO_ERR;
1297
}
1298
 
1299
/**
1300
 * Remove a nodelist from a document
1301
 *
1302
 * \param doc   The document to remove the list from
1303
 * \param list  The list to remove
1304
 */
1305
void _dom_document_remove_nodelist(dom_document *doc,
1306
		dom_nodelist *list)
1307
{
1308
	struct dom_doc_nl *l;
1309
 
1310
	for (l = doc->nodelists; l; l = l->next) {
1311
		if (l->list == list)
1312
			break;
1313
	}
1314
 
1315
	if (l == NULL) {
1316
		/* This should never happen; we should probably abort here */
1317
		return;
1318
	}
1319
 
1320
	/* Remove from list */
1321
	if (l->prev != NULL)
1322
		l->prev->next = l->next;
1323
	else
1324
		doc->nodelists = l->next;
1325
 
1326
	if (l->next != NULL)
1327
		l->next->prev = l->prev;
1328
 
1329
	/* And free item */
1330
	free(l);
1331
}
1332
 
1333
/**
1334
 * Find element with certain ID in the subtree rooted at root
1335
 *
1336
 * \param root    The root element from where we start
1337
 * \param id      The ID of the target element
1338
 * \param result  The result element
1339
 * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
1340
 */
1341
dom_exception _dom_find_element_by_id(dom_node_internal *root,
1342
		dom_string *id, dom_element **result)
1343
{
1344
	dom_node_internal *node = root;
1345
 
1346
	*result = NULL;
1347
 
1348
	while (node != NULL) {
1349
		if (node->type == DOM_ELEMENT_NODE) {
1350
			dom_string *real_id;
1351
 
1352
			_dom_element_get_id((dom_element *) node, &real_id);
1353
			if (real_id != NULL) {
1354
				if (dom_string_isequal(real_id, id)) {
1355
					dom_string_unref(real_id);
1356
					*result = (dom_element *) node;
1357
					return DOM_NO_ERR;
1358
				}
1359
 
1360
				dom_string_unref(real_id);
1361
			}
1362
		}
1363
 
1364
		if (node->first_child != NULL) {
1365
			/* Has children */
1366
			node = node->first_child;
1367
		} else if (node->next != NULL) {
1368
			/* No children, but has siblings */
1369
			node = node->next;
1370
		} else {
1371
			/* No children or siblings.
1372
			 * Find first unvisited relation. */
1373
			dom_node_internal *parent = node->parent;
1374
 
1375
			while (parent != root &&
1376
					node == parent->last_child) {
1377
				node = parent;
1378
				parent = parent->parent;
1379
			}
1380
 
1381
			node = node->next;
1382
		}
1383
	}
1384
 
1385
	return DOM_NO_ERR;
1386
}
1387
 
1388
/**
1389
 * Duplicate a Node
1390
 *
1391
 * \param doc     The documen
1392
 * \param node    The node to duplicate
1393
 * \param deep    Whether to make a deep copy
1394
 * \param result  The returned node
1395
 * \param opt     Whether this is adopt or import operation
1396
 * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
1397
 */
1398
dom_exception dom_document_dup_node(dom_document *doc, dom_node *node,
1399
		bool deep, dom_node **result, dom_node_operation opt)
1400
{
1401
	dom_node_internal *n = (dom_node_internal *) node;
1402
	dom_node_internal *ret;
1403
	dom_exception err;
1404
	dom_node_internal *child, *r;
1405
	dom_user_data *ud;
1406
 
1407
	if (opt == DOM_NODE_ADOPTED && _dom_node_readonly(n))
1408
		return DOM_NO_MODIFICATION_ALLOWED_ERR;
1409
 
1410
	if (n->type == DOM_DOCUMENT_NODE ||
1411
			n->type == DOM_DOCUMENT_TYPE_NODE)
1412
		return DOM_NOT_SUPPORTED_ERR;
1413
 
1414
	err = dom_node_copy(node, &ret);
1415
	if (err != DOM_NO_ERR)
1416
		return err;
1417
 
1418
	if (n->type == DOM_ATTRIBUTE_NODE) {
1419
		_dom_attr_set_specified((dom_attr *) node, true);
1420
		deep = true;
1421
	}
1422
 
1423
	if (n->type == DOM_ENTITY_REFERENCE_NODE) {
1424
		deep = false;
1425
	}
1426
 
1427
	if (n->type == DOM_ELEMENT_NODE) {
1428
		/* Specified attributes are copyied but not default attributes,
1429
		 * if the document object hold all the default attributes, we
1430
		 * have nothing to do here */
1431
	}
1432
 
1433
	if (opt == DOM_NODE_ADOPTED && (n->type == DOM_ENTITY_NODE ||
1434
			n->type == DOM_NOTATION_NODE)) {
1435
		/* We did not support XML now */
1436
		return DOM_NOT_SUPPORTED_ERR;
1437
	}
1438
 
1439
	if (deep == true) {
1440
		child = ((dom_node_internal *) node)->first_child;
1441
		while (child != NULL) {
1442
			err = dom_document_import_node(doc, child, deep,
1443
					(void *) &r);
1444
			if (err != DOM_NO_ERR) {
1445
				dom_node_unref(ret);
1446
				return err;
1447
			}
1448
 
1449
			err = dom_node_append_child(ret, r, (void *) &r);
1450
			if (err != DOM_NO_ERR) {
1451
				dom_node_unref(ret);
1452
				dom_node_unref(r);
1453
				return err;
1454
			}
1455
			dom_node_unref(r);
1456
 
1457
			child = child->next;
1458
		}
1459
	}
1460
 
1461
	/* Call the dom_user_data_handlers */
1462
	ud = n->user_data;
1463
	while (ud != NULL) {
1464
		if (ud->handler != NULL) {
1465
			ud->handler(opt, ud->key, ud->data, node,
1466
					(dom_node *) ret);
1467
		}
1468
		ud = ud->next;
1469
	}
1470
 
1471
	*result = (dom_node *) ret;
1472
 
1473
	return DOM_NO_ERR;
1474
}
1475
 
1476
/**
1477
 * Try to destroy the document.
1478
 *
1479
 * \param doc  The instance of Document
1480
 *
1481
 * Delete the document if:
1482
 * 1. The refcnt reach zero
1483
 * 2. The pending list is empty
1484
 *
1485
 * else, do nothing.
1486
 */
1487
void _dom_document_try_destroy(dom_document *doc)
1488
{
1489
	if (doc->base.base.refcnt != 0 || doc->base.parent != NULL)
1490
		return;
1491
 
1492
	_dom_document_destroy((dom_node_internal *) doc);
1493
}
1494
 
1495
/**
1496
 * Set the ID attribute name of this document
1497
 *
1498
 * \param doc   The document object
1499
 * \param name  The ID name of the elements in this document
1500
 */
1501
void _dom_document_set_id_name(dom_document *doc, dom_string *name)
1502
{
1503
	if (doc->id_name != NULL)
1504
		dom_string_unref(doc->id_name);
1505
	doc->id_name = dom_string_ref(name);
1506
}
1507
 
1508
/*-----------------------------------------------------------------------*/
1509
/* Semi-internal API extensions for NetSurf */
1510
 
1511
dom_exception _dom_document_get_quirks_mode(dom_document *doc,
1512
		dom_document_quirks_mode *result)
1513
{
1514
	*result = doc->quirks;
1515
	return DOM_NO_ERR;
1516
}
1517
 
1518
dom_exception _dom_document_set_quirks_mode(dom_document *doc,
1519
		dom_document_quirks_mode quirks)
1520
{
1521
	doc->quirks = quirks;
1522
	return DOM_NO_ERR;
1523
}