1 /*
2 * Copyright (C) 2001-2003 Peter J Jones (pjones@pmade.org)
3 * All Rights Reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * 3. Neither the name of the Author nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * $Id: ait_impl.cpp 457246 2015-01-21 17:09:53Z satskyse $
35 * NOTE: This file was modified from its original version 0.6.0
36 * to fit the NCBI C++ Toolkit build framework and
37 * API and functionality requirements.
38 * Most importantly, it adds support for XML namespaces (see "namespace.hpp").
39 */
40
41 /** @file
42 * This file implements the ait_impl, xml::attributes::iterator,
43 * xml::attributes::const_iterator and xml::attributes::attr classes.
44 **/
45
46 // xmlwrapp includes
47 #include "ait_impl.hpp"
48 #include "deref_impl.hpp"
49 #include "utility.hpp"
50 #include <misc/xmlwrapp/attributes.hpp>
51 #include <misc/xmlwrapp/exception.hpp>
52
53 // standard includes
54 #include <algorithm>
55 #include <stdexcept>
56 #include <string.h>
57
58 // libxml2 includes
59 #include <libxml/tree.h>
60
61 using namespace xml;
62 using namespace xml::impl;
63
64
65 const char* kDerefError = "dereferencing non initialised or out of range iterator";
66 const char* kRefError = "referencing non initialised or out of range iterator";
67 const char* kAdvError = "advancing non initialised or out of range iterator";
68 const char* kInvalidDefaultIterError = "invalid default attribute iterator";
69
70
71 /*
72 * First we have the ait_impl class.
73 */
74
75 //####################################################################
ait_impl(xmlNodePtr node,xmlAttrPtr prop,bool from_find)76 ait_impl::ait_impl (xmlNodePtr node, xmlAttrPtr prop, bool from_find) :
77 from_find_(from_find) {
78 attr_.set_data(node, prop, false);
79 }
80 //####################################################################
ait_impl(xmlNodePtr node,phantom_attr * prop,bool from_find)81 ait_impl::ait_impl (xmlNodePtr node, phantom_attr* prop, bool from_find) :
82 from_find_(from_find) {
83 attr_.set_data(node, prop, true);
84 }
85 //####################################################################
ait_impl(const ait_impl & other)86 ait_impl::ait_impl (const ait_impl &other) :
87 attr_(other.attr_),
88 from_find_(other.from_find_)
89 {}
90 //####################################################################
operator =(const ait_impl & other)91 ait_impl& ait_impl::operator= (const ait_impl &other) {
92 ait_impl tmp(other);
93
94 attr_.swap(tmp.attr_);
95 std::swap(from_find_, tmp.from_find_);
96 return *this;
97 }
98 //####################################################################
get(void)99 xml::attributes::attr* ait_impl::get (void) {
100 return &attr_;
101 }
102 //####################################################################
operator ++(void)103 ait_impl& ait_impl::operator++ (void) {
104 if (from_find_)
105 throw xml::exception("cannot iterate using iterators "
106 "produced by find(...) methods");
107
108 // Here: the iterator cannot point to a default attribute because
109 // it is not produced by find(...) methods
110 if (attr_.prop_)
111 attr_.prop_ = static_cast<xmlAttrPtr>(attr_.prop_)->next;
112 else
113 throw xml::exception(kAdvError);
114 return *this;
115 }
116 //####################################################################
operator ++(int)117 ait_impl ait_impl::operator++ (int) {
118 ait_impl tmp(*this);
119 ++(*this);
120 return tmp;
121 }
122 //####################################################################
123
124 /*
125 * Member functions for the xml::attributes::iterator class.
126 */
127
128 //####################################################################
iterator(void)129 xml::attributes::iterator::iterator (void) {
130 pimpl_ = new ait_impl(0, static_cast<xmlAttrPtr>(0), false);
131 }
132 //####################################################################
iterator(void * node,void * prop,bool def_prop,bool from_find)133 xml::attributes::iterator::iterator (void *node, void *prop,
134 bool def_prop, bool from_find) {
135 if (def_prop)
136 pimpl_ = new ait_impl(static_cast<xmlNodePtr>(node),
137 static_cast<phantom_attr*>(prop), from_find);
138 else
139 pimpl_ = new ait_impl(static_cast<xmlNodePtr>(node),
140 static_cast<xmlAttrPtr>(prop), from_find);
141 }
142 //####################################################################
iterator(const iterator & other)143 xml::attributes::iterator::iterator (const iterator &other) {
144 pimpl_ = new ait_impl(*other.pimpl_);
145 }
146 //####################################################################
147 xml::attributes::iterator&
operator =(const iterator & other)148 xml::attributes::iterator::operator= (const iterator &other) {
149 iterator tmp(other);
150 swap(tmp);
151 return *this;
152 }
153 //####################################################################
swap(iterator & other)154 void xml::attributes::iterator::swap (iterator &other) {
155 std::swap(pimpl_, other.pimpl_);
156 }
157 //####################################################################
~iterator(void)158 xml::attributes::iterator::~iterator (void) {
159 delete pimpl_;
160 }
161 //####################################################################
162 xml::attributes::iterator::reference
operator *(void) const163 xml::attributes::iterator::operator* (void) const {
164 xml::attributes::attr* att = pimpl_->get();
165 if (att->normalize())
166 return * static_cast<xml::attributes::attr*>
167 (get_ptr_to_attr_instance(att));
168 throw xml::exception(kDerefError);
169 }
170 //####################################################################
171 xml::attributes::iterator::pointer
operator ->(void) const172 xml::attributes::iterator::operator-> (void) const {
173 xml::attributes::attr* att = pimpl_->get();
174 if (att->normalize())
175 return static_cast<xml::attributes::attr*>
176 (get_ptr_to_attr_instance(att));
177 throw xml::exception(kRefError);
178 }
179 //####################################################################
operator ++(void)180 xml::attributes::iterator& xml::attributes::iterator::operator++ (void) {
181 ++(*pimpl_);
182 return *this;
183 }
184 //####################################################################
operator ++(int)185 xml::attributes::iterator xml::attributes::iterator::operator++ (int) {
186 iterator tmp(*this);
187 ++(*this);
188 return tmp;
189 }
190 //####################################################################
191
192 /*
193 * Member functions for the xml::attributes::const_iterator class.
194 */
195
196 //####################################################################
const_iterator(void)197 xml::attributes::const_iterator::const_iterator (void) {
198 pimpl_ = new ait_impl(0, static_cast<xmlAttrPtr>(0), false);
199 }
200 //####################################################################
const_iterator(void * node,void * prop,bool def_prop,bool from_find)201 xml::attributes::const_iterator::const_iterator (void *node, void *prop,
202 bool def_prop,
203 bool from_find) {
204 if (def_prop)
205 pimpl_ = new ait_impl(static_cast<xmlNodePtr>(node),
206 static_cast<phantom_attr*>(prop), from_find);
207 else
208 pimpl_ = new ait_impl(static_cast<xmlNodePtr>(node),
209 static_cast<xmlAttrPtr>(prop), from_find);
210 }
211 //####################################################################
const_iterator(const const_iterator & other)212 xml::attributes::const_iterator::const_iterator (const const_iterator &other) {
213 pimpl_ = new ait_impl(*other.pimpl_);
214 }
215 //####################################################################
const_iterator(const iterator & other)216 xml::attributes::const_iterator::const_iterator (const iterator &other) {
217 pimpl_ = new ait_impl(*other.pimpl_);
218 }
219 //####################################################################
220 xml::attributes::const_iterator&
operator =(const const_iterator & other)221 xml::attributes::const_iterator::operator= (const const_iterator &other) {
222 const_iterator tmp(other);
223 swap(tmp);
224 return *this;
225 }
226 //####################################################################
swap(const_iterator & other)227 void xml::attributes::const_iterator::swap (const_iterator &other) {
228 std::swap(pimpl_, other.pimpl_);
229 }
230 //####################################################################
~const_iterator(void)231 xml::attributes::const_iterator::~const_iterator (void) {
232 delete pimpl_;
233 }
234 //####################################################################
235 xml::attributes::const_iterator::reference
operator *(void) const236 xml::attributes::const_iterator::operator* (void) const {
237 xml::attributes::attr* att = pimpl_->get();
238 if (att->normalize())
239 return * static_cast<xml::attributes::attr*>
240 (get_ptr_to_attr_instance(att));
241 throw xml::exception(kDerefError);
242 }
243 //####################################################################
244 xml::attributes::const_iterator::pointer
operator ->(void) const245 xml::attributes::const_iterator::operator-> (void) const {
246 xml::attributes::attr* att = pimpl_->get();
247 if (att->normalize())
248 return static_cast<xml::attributes::attr*>
249 (get_ptr_to_attr_instance(att));
250 throw xml::exception(kRefError);
251 }
252 //####################################################################
253 xml::attributes::const_iterator&
operator ++(void)254 xml::attributes::const_iterator::operator++ (void) {
255 ++(*pimpl_);
256 return *this;
257 }
258 //####################################################################
259 xml::attributes::const_iterator
operator ++(int)260 xml::attributes::const_iterator::operator++ (int) {
261 const_iterator tmp(*this);
262 ++(*this);
263 return tmp;
264 }
265 //####################################################################
266
267 /*
268 * Member functions for the xml::attributes::attr class.
269 */
270
271 //####################################################################
attr(void)272 xml::attributes::attr::attr (void) : xmlnode_(0), prop_(0), phantom_prop_(0)
273 {}
274 //####################################################################
attr(const attr & other)275 xml::attributes::attr::attr (const attr &other) :
276 xmlnode_(other.xmlnode_), prop_(other.prop_),
277 phantom_prop_(other.phantom_prop_), value_(other.value_)
278 {}
279 //####################################################################
operator =(const attr & other)280 xml::attributes::attr& xml::attributes::attr::operator= (const attr &other) {
281 attr tmp(other);
282 swap(tmp);
283 return *this;
284 }
285 //####################################################################
swap(attr & other)286 void xml::attributes::attr::swap (attr &other) {
287 std::swap(xmlnode_, other.xmlnode_);
288 std::swap(prop_, other.prop_);
289 std::swap(phantom_prop_, other.phantom_prop_);
290 value_.swap(other.value_);
291 }
292 //####################################################################
set_data(void * node,void * prop,bool def_prop)293 void xml::attributes::attr::set_data (void *node, void *prop, bool def_prop) {
294 xmlnode_ = node;
295 value_.erase();
296 if (def_prop) {
297 prop_ = 0;
298 phantom_prop_ = prop;
299 }
300 else {
301 prop_ = prop;
302 phantom_prop_ = 0;
303 }
304 }
305 //####################################################################
normalize(void) const306 void * xml::attributes::attr::normalize (void) const {
307 if (!xmlnode_) return NULL;
308 if (prop_) return prop_;
309
310 if (phantom_prop_) {
311 if (static_cast<phantom_attr*>(phantom_prop_)->prop_)
312 return static_cast<phantom_attr*>(phantom_prop_)->prop_;
313 if (static_cast<phantom_attr*>(phantom_prop_)->def_prop_)
314 return static_cast<phantom_attr*>(phantom_prop_)->def_prop_;
315 }
316 return NULL;
317 }
318 //####################################################################
get_node(void) const319 void * xml::attributes::attr::get_node(void) const {
320 return xmlnode_;
321 }
322 //####################################################################
operator ==(const xml::attributes::attr & other) const323 bool xml::attributes::attr::operator==
324 (const xml::attributes::attr & other) const {
325 return normalize() == other.normalize();
326 }
327 //####################################################################
is_default(void) const328 bool xml::attributes::attr::is_default (void) const {
329 if (phantom_prop_ && (!static_cast<phantom_attr*>(phantom_prop_)->prop_))
330 return true;
331 return false;
332 }
333 //####################################################################
get_name(void) const334 const char* xml::attributes::attr::get_name (void) const {
335 if (is_default()) {
336 xmlAttributePtr dprop = static_cast<phantom_attr*>(phantom_prop_)->def_prop_;
337 if (!dprop)
338 throw xml::exception(kInvalidDefaultIterError);
339 return reinterpret_cast<const char*>(dprop->name);
340 }
341 if (prop_) {
342 const xmlChar * name = static_cast<xmlAttrPtr>(prop_)->name;
343 return reinterpret_cast<const char*>(name);
344 }
345 const xmlChar * name = static_cast<phantom_attr*>(phantom_prop_)->prop_->name;
346 return reinterpret_cast<const char*>(name);
347 }
348 //####################################################################
get_value(void) const349 const char* xml::attributes::attr::get_value (void) const {
350 if (is_default()) {
351 xmlAttributePtr dprop = static_cast<phantom_attr*>(phantom_prop_)->def_prop_;
352 if (!dprop)
353 throw xml::exception(kInvalidDefaultIterError);
354 if (dprop->defaultValue)
355 return reinterpret_cast<const char*>(dprop->defaultValue);
356 return "";
357 }
358
359 xmlChar *tmpstr;
360 if (prop_) {
361 tmpstr = xmlNodeListGetString(reinterpret_cast<xmlNodePtr>(xmlnode_)->doc,
362 reinterpret_cast<xmlAttrPtr>(prop_)->children,
363 1);
364 }
365 else {
366 tmpstr = xmlNodeListGetString(reinterpret_cast<xmlNodePtr>(xmlnode_)->doc,
367 reinterpret_cast<phantom_attr*>(phantom_prop_)->prop_->children,
368 1);
369 }
370 if (tmpstr == 0)
371 return "";
372
373 xmlchar_helper helper(tmpstr);
374 value_.assign(reinterpret_cast<const char*>(tmpstr));
375 return value_.c_str();
376 }
377 //####################################################################
378 xml::ns
get_namespace(xml::ns::ns_safety_type type) const379 xml::attributes::attr::get_namespace (xml::ns::ns_safety_type type) const {
380 xmlNs * definition;
381 if (is_default()) {
382 definition = static_cast<xmlNs*>(resolve_default_attr_ns());
383 }
384 else {
385 xmlAttrPtr prop = reinterpret_cast<xmlAttrPtr>(prop_);
386 if (!prop_)
387 prop = reinterpret_cast<phantom_attr*>(phantom_prop_)->prop_;
388 definition = prop->ns;
389 }
390
391 if (type == xml::ns::type_safe_ns) {
392 return definition
393 ? xml::ns(reinterpret_cast<const char*>(definition->prefix),
394 reinterpret_cast<const char*>(definition->href))
395 : xml::ns(xml::ns::type_void);
396 }
397 // unsafe namespace
398 return xml::attributes::createUnsafeNamespace(definition);
399 }
400 //####################################################################
401 // Resolves a namespace for a default attribute.
402 // If it cannot resolve it then an exception is thrown.
403 // NULL is returned if no namespace should be used.
resolve_default_attr_ns(void) const404 void *xml::attributes::attr::resolve_default_attr_ns (void) const {
405 if (!is_default())
406 throw xml::exception("internal library error: "
407 "resolving non-default attribute namespace");
408
409 xmlAttributePtr dprop = static_cast<phantom_attr*>(phantom_prop_)->def_prop_;
410 if (!dprop)
411 throw xml::exception(kInvalidDefaultIterError);
412 xmlNs * definition(xmlSearchNs(NULL, reinterpret_cast<xmlNode*>(xmlnode_),
413 dprop->prefix));
414 if (dprop->prefix)
415 if (!definition)
416 throw xml::exception("cannot resolve default attribute namespace");
417 return definition;
418 }
419 //####################################################################
420 // This converts a default attribute to a regular one
convert(void)421 void xml::attributes::attr::convert (void) {
422 if (!is_default())
423 return;
424
425 xmlNs * definition = static_cast<xmlNs*>(resolve_default_attr_ns());
426 xmlAttributePtr dprop = static_cast<phantom_attr*>(phantom_prop_)->def_prop_;
427 if (!dprop)
428 throw xml::exception(kInvalidDefaultIterError);
429 xmlAttrPtr new_attr = xmlSetNsProp(reinterpret_cast<xmlNode*>(xmlnode_),
430 definition,
431 dprop->name,
432 dprop->defaultValue);
433 if (!new_attr)
434 throw xml::exception("cannot convert default attribute into a regular one");
435
436 // It's not a default any more
437 static_cast<phantom_attr*>(phantom_prop_)->def_prop_ = NULL;
438 static_cast<phantom_attr*>(phantom_prop_)->prop_ = new_attr;
439 return;
440 }
441 //####################################################################
set_value(const char * value)442 void xml::attributes::attr::set_value (const char* value) {
443 convert();
444 xmlAttrPtr prop = reinterpret_cast<xmlAttrPtr>(normalize());
445 xmlSetNsProp(reinterpret_cast<xmlNode*>(xmlnode_),
446 prop->ns,
447 prop->name,
448 reinterpret_cast<const xmlChar*>(value));
449 return;
450 }
451 //####################################################################
erase_namespace(void)452 void xml::attributes::attr::erase_namespace (void) {
453 convert();
454 xmlAttrPtr prop = reinterpret_cast<xmlAttrPtr>(normalize());
455 prop->ns = NULL;
456 }
457 //####################################################################
set_namespace(const char * prefix)458 xml::ns xml::attributes::attr::set_namespace (const char *prefix) {
459 if (!prefix || prefix[0] == '\0') {
460 erase_namespace();
461 return xml::attributes::createUnsafeNamespace(NULL);
462 }
463
464 convert();
465 xmlAttrPtr prop = reinterpret_cast<xmlAttrPtr>(normalize());
466 xmlNs * definition(xmlSearchNs(NULL, reinterpret_cast<xmlNode*>(xmlnode_),
467 reinterpret_cast<const xmlChar*>(prefix)));
468 if (!definition)
469 throw xml::exception("Namespace definition is not found");
470 prop->ns = definition;
471 return xml::attributes::createUnsafeNamespace(definition);
472 }
473 //####################################################################
set_namespace(const xml::ns & name_space)474 xml::ns xml::attributes::attr::set_namespace (const xml::ns &name_space) {
475 if (name_space.is_void()) {
476 erase_namespace();
477 return xml::attributes::createUnsafeNamespace(NULL);
478 }
479
480 convert();
481 xmlAttrPtr prop = reinterpret_cast<xmlAttrPtr>(normalize());
482
483 if (!name_space.is_safe()) {
484 prop->ns = reinterpret_cast<xmlNs*>(getUnsafeNamespacePointer(name_space));
485 }
486 else {
487 const char * prefix(name_space.get_prefix());
488 if (prefix[0] == '\0')
489 prefix = NULL;
490 xmlNs * definition(xmlSearchNs(NULL, reinterpret_cast<xmlNode*>(xmlnode_),
491 reinterpret_cast<const xmlChar*>(prefix)));
492 if (!definition)
493 throw xml::exception("Namespace definition is not found");
494 if (!xmlStrEqual(definition->href, reinterpret_cast<const xmlChar*>(name_space.get_uri())))
495 throw xml::exception("Namespace definition URI differs to the given");
496 prop->ns = definition;
497 }
498 return createUnsafeNamespace(prop->ns);
499 }
500 //####################################################################
501
502 /*
503 * Now some friend functions
504 */
505
506 //####################################################################
507 namespace xml {
508
509 namespace impl {
510 //####################################################################
find_prop(xmlNodePtr xmlnode,const char * name,const ns * nspace)511 xmlAttrPtr find_prop (xmlNodePtr xmlnode,
512 const char *name, const ns *nspace) {
513
514 // The similar check is in libxml2 static function
515 // xmlGetPropNodeInternal(...)
516 if ( (xmlnode == NULL) ||
517 (xmlnode->type != XML_ELEMENT_NODE) ||
518 (name == NULL) )
519 return NULL;
520
521 const ns * ns_to_match = nspace;
522 const char * name_to_match = name;
523
524 // Check first if the name is qualified
525 const char * column = strchr(name, ':');
526
527 if (column) {
528 if (nspace)
529 return NULL; // Both namespace and the name is qualified
530
531 if (column == name)
532 return NULL; // The name starts with :
533
534 if (*(column + 1) == '\0')
535 return NULL; // No attribute name is given
536
537 std::string prefix(name, column - name);
538 xmlNsPtr resolved_ns = xmlSearchNs(xmlnode->doc,
539 xmlnode,
540 reinterpret_cast<const xmlChar*>(prefix.c_str()));
541 if (!resolved_ns)
542 return NULL; // No such namespace found
543
544 name_to_match = column + 1;
545 ns_to_match = new ns(reinterpret_cast<const char *>(resolved_ns->prefix),
546 reinterpret_cast<const char *>(resolved_ns->href));
547 }
548
549 xmlAttrPtr prop = xmlnode->properties;
550 for (; prop != NULL; prop = prop->next) {
551 if (xmlStrEqual(prop->name,
552 reinterpret_cast<const xmlChar*>(name_to_match))) {
553 if (ns_util::attr_ns_match(prop, ns_to_match)) {
554 if (ns_to_match != nspace)
555 delete ns_to_match;
556 return prop;
557 }
558 }
559 }
560
561 if (ns_to_match != nspace)
562 delete ns_to_match;
563 return NULL;
564 }
565 //####################################################################
find_default_prop(xmlNodePtr xmlnode,const char * name,const ns * nspace)566 phantom_attr* find_default_prop (xmlNodePtr xmlnode,
567 const char *name, const ns *nspace) {
568 if (xmlnode->doc != 0) {
569 xmlAttributePtr dtd_attr = 0;
570 const xmlChar* prefix = 0;
571
572 if (nspace && strlen(nspace->get_prefix()) > 0)
573 prefix = reinterpret_cast<const xmlChar*>(nspace->get_prefix());
574
575 if (xmlnode->doc->intSubset != 0) {
576 if (nspace)
577 dtd_attr = xmlGetDtdQAttrDesc(xmlnode->doc->intSubset,
578 xmlnode->name,
579 reinterpret_cast<const xmlChar*>(name),
580 prefix);
581 else
582 dtd_attr = xmlGetDtdAttrDesc(xmlnode->doc->intSubset,
583 xmlnode->name,
584 reinterpret_cast<const xmlChar*>(name));
585 }
586
587 if (dtd_attr == 0 && xmlnode->doc->extSubset != 0) {
588 if (nspace)
589 dtd_attr = xmlGetDtdQAttrDesc(xmlnode->doc->extSubset,
590 xmlnode->name,
591 reinterpret_cast<const xmlChar*>(name),
592 prefix);
593 else
594 dtd_attr = xmlGetDtdAttrDesc(xmlnode->doc->extSubset,
595 xmlnode->name,
596 reinterpret_cast<const xmlChar*>(name));
597 }
598
599 if (dtd_attr != 0 && dtd_attr->defaultValue != 0) {
600
601 node_private_data * node_data = attach_node_private_data(xmlnode);
602
603
604 // Found, now check the phantom attributes list attached to the
605 // node
606 phantom_attr * current = node_data->phantom_attrs_;
607 while (current != NULL) {
608 if (current->def_prop_ == dtd_attr)
609 return current;
610 current = current->next;
611 }
612
613 // Not found. Create a new phantom_attr structure
614 phantom_attr * new_phantom = new phantom_attr;
615 memset( new_phantom, 0, sizeof( phantom_attr ) );
616 new_phantom->def_prop_ = dtd_attr;
617
618 current = node_data->phantom_attrs_;
619 new_phantom->next = current;
620 node_data->phantom_attrs_ = new_phantom;
621 return new_phantom;
622 }
623 }
624 return NULL;
625 }
626 }
627
628 //####################################################################
operator ==(const attributes::iterator & lhs,const attributes::iterator & rhs)629 bool operator== (const attributes::iterator &lhs,
630 const attributes::iterator &rhs) {
631 return *(lhs.pimpl_) == *(rhs.pimpl_);
632 }
633 //####################################################################
operator !=(const attributes::iterator & lhs,const attributes::iterator & rhs)634 bool operator!= (const attributes::iterator &lhs,
635 const attributes::iterator &rhs) {
636 return !(lhs == rhs);
637 }
638 //####################################################################
operator ==(const attributes::const_iterator & lhs,const attributes::const_iterator & rhs)639 bool operator== (const attributes::const_iterator &lhs,
640 const attributes::const_iterator &rhs) {
641 return *(lhs.pimpl_) == *(rhs.pimpl_);
642 }
643 //####################################################################
operator !=(const attributes::const_iterator & lhs,const attributes::const_iterator & rhs)644 bool operator!= (const attributes::const_iterator &lhs,
645 const attributes::const_iterator &rhs) {
646 return !(lhs == rhs);
647 }
648 //####################################################################
649 namespace impl {
operator ==(const ait_impl & lhs,const ait_impl & rhs)650 bool operator== (const ait_impl &lhs, const ait_impl &rhs) {
651 return ((lhs.attr_.xmlnode_ == rhs.attr_.xmlnode_) &&
652 (lhs.attr_.normalize() == rhs.attr_.normalize()));
653 }
654 //####################################################################
operator !=(const ait_impl & lhs,const ait_impl & rhs)655 bool operator!= (const ait_impl &lhs, const ait_impl &rhs) {
656 return !(lhs == rhs);
657 }
658 }
659 //####################################################################
660 }
661 //####################################################################
662