https://issues.shibboleth.net/jira/browse/CPPXT-18
[shibboleth/cpp-xmltooling.git] / xmltooling / AbstractXMLObject.cpp
1 /*
2 *  Copyright 2001-2007 Internet2
3  *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * AbstractXMLObject.cpp
19  *
20  * An abstract implementation of XMLObject.
21  */
22
23 #include "internal.h"
24 #include "AbstractXMLObject.h"
25 #include "exceptions.h"
26
27 #include <algorithm>
28
29 using namespace xmltooling;
30
31 AbstractXMLObject::AbstractXMLObject(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType)
32     : m_log(logging::Category::getInstance(XMLTOOLING_LOGCAT".XMLObject")),
33         m_schemaLocation(NULL), m_noNamespaceSchemaLocation(NULL), m_nil(xmlconstants::XML_BOOL_NULL),
34         m_parent(NULL), m_elementQname(nsURI, localName, prefix), m_typeQname(NULL)
35 {
36     addNamespace(Namespace(nsURI, prefix));
37     if (schemaType) {
38         m_typeQname = new QName(*schemaType);
39         addNamespace(Namespace(m_typeQname->getNamespaceURI(), m_typeQname->getPrefix()));
40     }
41 }
42
43 AbstractXMLObject::AbstractXMLObject(const AbstractXMLObject& src)
44     : m_namespaces(src.m_namespaces), m_log(src.m_log), m_schemaLocation(XMLString::replicate(src.m_schemaLocation)),
45         m_noNamespaceSchemaLocation(XMLString::replicate(src.m_noNamespaceSchemaLocation)), m_nil(src.m_nil),
46         m_parent(NULL), m_elementQname(src.m_elementQname), m_typeQname(NULL)
47 {
48     if (src.m_typeQname)
49         m_typeQname=new QName(*src.m_typeQname);
50 }
51
52 AbstractXMLObject::~AbstractXMLObject()
53 {
54     delete m_typeQname;
55     xercesc::XMLString::release(&m_schemaLocation);
56     xercesc::XMLString::release(&m_noNamespaceSchemaLocation);
57 }
58
59 void XMLObject::setNil(const XMLCh* value) {
60     if (value) {
61         switch (*value) {
62             case xercesc::chLatin_t:
63                 nil(xmlconstants::XML_BOOL_TRUE);
64                 break;
65             case xercesc::chLatin_f:
66                 nil(xmlconstants::XML_BOOL_FALSE);
67                 break;
68             case xercesc::chDigit_1:
69                 nil(xmlconstants::XML_BOOL_ONE);
70                 break;
71             case xercesc::chDigit_0:
72                 nil(xmlconstants::XML_BOOL_ZERO);
73                 break;
74             default:
75                 nil(xmlconstants::XML_BOOL_NULL);
76         }
77     }
78     else {
79         nil(xmlconstants::XML_BOOL_NULL);
80     }
81 }
82
83 XMLCh* AbstractXMLObject::prepareForAssignment(XMLCh* oldValue, const XMLCh* newValue)
84 {
85     if (!XMLString::equals(oldValue,newValue)) {
86         releaseThisandParentDOM();
87         XMLCh* newString = XMLString::replicate(newValue);
88         XMLString::release(&oldValue);
89         return newString;
90     }
91     return oldValue;
92 }
93
94 QName* AbstractXMLObject::prepareForAssignment(QName* oldValue, const QName* newValue)
95 {
96     if (!oldValue) {
97         if (newValue) {
98             releaseThisandParentDOM();
99             Namespace newNamespace(newValue->getNamespaceURI(), newValue->getPrefix());
100             addNamespace(newNamespace);
101             return new QName(*newValue);
102         }
103         return NULL;
104     }
105
106     delete oldValue;
107     releaseThisandParentDOM();
108     if (newValue) {
109         Namespace newNamespace(newValue->getNamespaceURI(), newValue->getPrefix());
110         addNamespace(newNamespace);
111         return new QName(*newValue);
112     }
113     return NULL;
114 }
115
116 DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, const DateTime* newValue)
117 {
118     if (!oldValue) {
119         if (newValue) {
120             releaseThisandParentDOM();
121             return new DateTime(*newValue);
122         }
123         return NULL;
124     }
125
126     delete oldValue;
127     releaseThisandParentDOM();
128     return newValue ? new DateTime(*newValue) : NULL;
129 }
130
131 DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, time_t newValue, bool duration)
132 {
133     delete oldValue;
134     releaseThisandParentDOM();
135     DateTime* ret = new DateTime(newValue);
136     if (duration)
137         ret->parseDuration();
138     else
139         ret->parseDateTime();
140     return ret;
141 }
142
143 DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, const XMLCh* newValue, bool duration)
144 {
145     delete oldValue;
146     releaseThisandParentDOM();
147     DateTime* ret = new DateTime(newValue);
148     if (duration)
149         ret->parseDuration();
150     else
151         ret->parseDateTime();
152     return ret;
153 }
154
155 XMLObject* AbstractXMLObject::prepareForAssignment(XMLObject* oldValue, XMLObject* newValue)
156 {
157     if (newValue && newValue->hasParent())
158         throw XMLObjectException("child XMLObject cannot be added - it is already the child of another XMLObject");
159
160     if (!oldValue) {
161         if (newValue) {
162             releaseThisandParentDOM();
163             newValue->setParent(this);
164         }
165         return newValue;
166     }
167
168     if (oldValue != newValue) {
169         delete oldValue;
170         releaseThisandParentDOM();
171         if (newValue)
172             newValue->setParent(this);
173     }
174
175     return newValue;
176 }
177
178 void AbstractXMLObject::detach()
179 {
180     if (!getParent())
181         return;
182     else if (getParent()->hasParent())
183         throw XMLObjectException("Cannot detach an object whose parent is itself a child.");
184
185     // Pull ourselves out of the parent and then blast him.
186     getParent()->removeChild(this);
187     delete m_parent;
188     m_parent = NULL;
189 }