Change license header.
[shibboleth/sp.git] / shibsp / util / DOMPropertySet.cpp
1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20
21 /**
22  * DOMPropertySet.cpp
23  * 
24  * DOM-based property set implementation.
25  */
26
27 #include "internal.h"
28 #include "util/DOMPropertySet.h"
29
30 #include <algorithm>
31 #include <xmltooling/util/NDC.h>
32 #include <xmltooling/util/XMLConstants.h>
33
34 using namespace shibsp;
35 using namespace xmltooling;
36 using namespace xercesc;
37 using namespace std;
38
39 PropertySet::PropertySet()
40 {
41 }
42
43 PropertySet::~PropertySet()
44 {
45 }
46
47 DOMPropertySet::DOMPropertySet() : m_parent(nullptr), m_root(nullptr)
48 {
49 }
50
51 DOMPropertySet::~DOMPropertySet()
52 {
53     for (map<string,pair<char*,const XMLCh*> >::iterator i=m_map.begin(); i!=m_map.end(); i++)
54         XMLString::release(&(i->second.first));
55     for_each(m_nested.begin(),m_nested.end(),cleanup_pair<string,DOMPropertySet>());
56 }
57
58 const PropertySet* DOMPropertySet::getParent() const
59 {
60     return m_parent;
61 }
62
63 void DOMPropertySet::setParent(const PropertySet* parent)
64 {
65     m_parent = parent;
66 }
67
68 const DOMElement* DOMPropertySet::getElement() const
69 {
70     return m_root;
71 }
72
73 void DOMPropertySet::load(
74     const DOMElement* e,
75     Category* log,
76     DOMNodeFilter* filter,
77     const std::map<std::string,std::string>* remapper
78     )
79 {
80 #ifdef _DEBUG
81     NDC ndc("load");
82 #endif
83     if (!e)
84         return;
85     m_root=e;
86     if (!log)
87         log = &Category::getInstance(SHIBSP_LOGCAT".PropertySet");
88
89     // Process each attribute as a property.
90     DOMNamedNodeMap* attrs=m_root->getAttributes();
91     for (XMLSize_t i=0; i<attrs->getLength(); i++) {
92         DOMNode* a=attrs->item(i);
93         if (!XMLString::compareString(a->getNamespaceURI(),xmlconstants::XMLNS_NS))
94             continue;
95         char* val=XMLString::transcode(a->getNodeValue());
96         if (val && *val) {
97             auto_ptr_char ns(a->getNamespaceURI());
98             auto_ptr_char name(a->getLocalName());
99             const char* realname=name.get();
100             map<string,string>::const_iterator remap;
101             if (remapper) {
102                 remap=remapper->find(realname);
103                 if (remap!=remapper->end()) {
104                     log->warn("deprecation - remapping property (%s) to (%s)",realname,remap->second.c_str());
105                     realname=remap->second.c_str();
106                 }
107             }
108             if (ns.get()) {
109                 if (remapper && (remap=remapper->find(ns.get()))!=remapper->end())
110                     m_map[string("{") + remap->second.c_str() + '}' + realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
111                 else
112                     m_map[string("{") + ns.get() + '}' + realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
113                 log->debug("added property {%s}%s (%s)",ns.get(),realname,val);
114             }
115             else {
116                 m_map[realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
117                 log->debug("added property %s (%s)",realname,val);
118             }
119         }
120     }
121     
122     // Process non-excluded elements as nested sets.
123     DOMTreeWalker* walker=
124         static_cast<DOMDocumentTraversal*>(
125             m_root->getOwnerDocument())->createTreeWalker(const_cast<DOMElement*>(m_root),DOMNodeFilter::SHOW_ELEMENT,filter,false
126             );
127     e=static_cast<DOMElement*>(walker->firstChild());
128     while (e) {
129         auto_ptr_char ns(e->getNamespaceURI());
130         auto_ptr_char name(e->getLocalName());
131         const char* realname=name.get();
132         map<string,string>::const_iterator remap;
133         if (remapper) {
134             remap=remapper->find(realname);
135             if (remap!=remapper->end()) {
136                 log->warn("deprecation - remapping nested property set (%s) to (%s)",realname,remap->second.c_str());
137                 realname=remap->second.c_str();
138             }
139         }
140         string key;
141         if (ns.get()) {
142             if (remapper && (remap=remapper->find(ns.get()))!=remapper->end())
143                 key=string("{") + remap->second.c_str() + '}' + realname;
144             else
145                 key=string("{") + ns.get() + '}' + realname;
146         }
147         else
148             key=realname;
149         if (m_nested.find(key)!=m_nested.end())
150             log->warn("load() skipping duplicate property set: %s",key.c_str());
151         else {
152             DOMPropertySet* set=new DOMPropertySet();
153             set->load(e,log,filter,remapper);
154             m_nested[key]=set;
155             log->debug("added nested property set: %s",key.c_str());
156         }
157         e=static_cast<DOMElement*>(walker->nextSibling());
158     }
159     walker->release();
160 }
161
162 pair<bool,bool> DOMPropertySet::getBool(const char* name, const char* ns) const
163 {
164     map<string,pair<char*,const XMLCh*> >::const_iterator i;
165
166     if (ns)
167         i=m_map.find(string("{") + ns + '}' + name);
168     else
169         i=m_map.find(name);
170
171     if (i!=m_map.end())
172         return make_pair(true,(!strcmp(i->second.first,"true") || !strcmp(i->second.first,"1")));
173     else if (m_parent)
174         return m_parent->getBool(name,ns);
175     return make_pair(false,false);
176 }
177
178 pair<bool,const char*> DOMPropertySet::getString(const char* name, const char* ns) const
179 {
180     pair<bool,const char*> ret(false,nullptr);
181     map<string,pair<char*,const XMLCh*> >::const_iterator i;
182
183     if (ns)
184         i=m_map.find(string("{") + ns + '}' + name);
185     else
186         i=m_map.find(name);
187
188     if (i!=m_map.end())
189         return pair<bool,const char*>(true,i->second.first);
190     else if (m_parent)
191         return m_parent->getString(name,ns);
192     return pair<bool,const char*>(false,nullptr);
193 }
194
195 pair<bool,const XMLCh*> DOMPropertySet::getXMLString(const char* name, const char* ns) const
196 {
197     map<string,pair<char*,const XMLCh*> >::const_iterator i;
198
199     if (ns)
200         i=m_map.find(string("{") + ns + '}' + name);
201     else
202         i=m_map.find(name);
203
204     if (i!=m_map.end())
205         return make_pair(true,i->second.second);
206     else if (m_parent)
207         return m_parent->getXMLString(name,ns);
208     return pair<bool,const XMLCh*>(false,nullptr);
209 }
210
211 pair<bool,unsigned int> DOMPropertySet::getUnsignedInt(const char* name, const char* ns) const
212 {
213     map<string,pair<char*,const XMLCh*> >::const_iterator i;
214
215     if (ns)
216         i=m_map.find(string("{") + ns + '}' + name);
217     else
218         i=m_map.find(name);
219
220     if (i!=m_map.end())
221         return pair<bool,unsigned int>(true,strtol(i->second.first,nullptr,10));
222     else if (m_parent)
223         return m_parent->getUnsignedInt(name,ns);
224     return pair<bool,unsigned int>(false,0);
225 }
226
227 pair<bool,int> DOMPropertySet::getInt(const char* name, const char* ns) const
228 {
229     map<string,pair<char*,const XMLCh*> >::const_iterator i;
230
231     if (ns)
232         i=m_map.find(string("{") + ns + '}' + name);
233     else
234         i=m_map.find(name);
235
236     if (i!=m_map.end())
237         return pair<bool,int>(true,atoi(i->second.first));
238     else if (m_parent)
239         return m_parent->getInt(name,ns);
240     return pair<bool,int>(false,0);
241 }
242
243 void DOMPropertySet::getAll(std::map<std::string,const char*>& properties) const
244 {
245     if (m_parent)
246         m_parent->getAll(properties);
247     for (map< string,pair<char*,const XMLCh*> >::const_iterator i = m_map.begin(); i != m_map.end(); ++i)
248         properties[i->first] = i->second.first;
249 }
250
251 const PropertySet* DOMPropertySet::getPropertySet(const char* name, const char* ns) const
252 {
253     map<string,DOMPropertySet*>::const_iterator i;
254
255     if (ns)
256         i=m_nested.find(string("{") + ns + '}' + name);
257     else
258         i=m_nested.find(name);
259
260     return (i!=m_nested.end()) ? i->second : (m_parent ? m_parent->getPropertySet(name,ns) : nullptr);
261 }
262
263 bool DOMPropertySet::setProperty(const char* name, const char* val, const char* ns)
264 {
265     string propname = ns ? (string("{") + ns + "}" + name) : name;
266
267     // Erase existing property.
268     if (m_map.count(propname) > 0) {
269         XMLString::release(&m_map[propname].first);
270         m_map.erase(propname);
271     }
272
273     char* dup = XMLString::replicate(val);
274     auto_ptr_XMLCh widedup(val);
275     m_injected.push_back(widedup.get());
276     m_map[propname] = make_pair(dup, m_injected.back().c_str());
277
278     return true;
279 }