Boost code changes
[shibboleth/cpp-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 }
56
57 const PropertySet* DOMPropertySet::getParent() const
58 {
59     return m_parent;
60 }
61
62 void DOMPropertySet::setParent(const PropertySet* parent)
63 {
64     m_parent = parent;
65 }
66
67 const DOMElement* DOMPropertySet::getElement() const
68 {
69     return m_root;
70 }
71
72 void DOMPropertySet::load(
73     const DOMElement* e,
74     Category* log,
75     DOMNodeFilter* filter,
76     const std::map<std::string,std::string>* remapper
77     )
78 {
79 #ifdef _DEBUG
80     NDC ndc("load");
81 #endif
82     if (!e)
83         return;
84     m_root=e;
85     if (!log)
86         log = &Category::getInstance(SHIBSP_LOGCAT".PropertySet");
87
88     // Process each attribute as a property.
89     DOMNamedNodeMap* attrs=m_root->getAttributes();
90     for (XMLSize_t i=0; i<attrs->getLength(); i++) {
91         DOMNode* a=attrs->item(i);
92         if (!XMLString::compareString(a->getNamespaceURI(),xmlconstants::XMLNS_NS))
93             continue;
94         char* val=XMLString::transcode(a->getNodeValue());
95         if (val && *val) {
96             auto_ptr_char ns(a->getNamespaceURI());
97             auto_ptr_char name(a->getLocalName());
98             const char* realname=name.get();
99             map<string,string>::const_iterator remap;
100             if (remapper) {
101                 remap=remapper->find(realname);
102                 if (remap!=remapper->end()) {
103                     log->warn("deprecation - remapping property (%s) to (%s)",realname,remap->second.c_str());
104                     realname=remap->second.c_str();
105                 }
106             }
107             if (ns.get()) {
108                 if (remapper && (remap=remapper->find(ns.get()))!=remapper->end())
109                     m_map[string("{") + remap->second.c_str() + '}' + realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
110                 else
111                     m_map[string("{") + ns.get() + '}' + realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
112                 log->debug("added property {%s}%s (%s)",ns.get(),realname,val);
113             }
114             else {
115                 m_map[realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
116                 log->debug("added property %s (%s)",realname,val);
117             }
118         }
119     }
120     
121     // Process non-excluded elements as nested sets.
122     DOMTreeWalker* walker =
123         static_cast<DOMDocumentTraversal*>(
124             m_root->getOwnerDocument())->createTreeWalker(const_cast<DOMElement*>(m_root),DOMNodeFilter::SHOW_ELEMENT,filter,false
125             );
126     e = static_cast<DOMElement*>(walker->firstChild());
127     while (e) {
128         auto_ptr_char ns(e->getNamespaceURI());
129         auto_ptr_char name(e->getLocalName());
130         const char* realname=name.get();
131         map<string,string>::const_iterator remap;
132         if (remapper) {
133             remap = remapper->find(realname);
134             if (remap != remapper->end()) {
135                 log->warn("deprecation - remapping nested property set (%s) to (%s)", realname, remap->second.c_str());
136                 realname = remap->second.c_str();
137             }
138         }
139         string key;
140         if (ns.get()) {
141             if (remapper && (remap = remapper->find(ns.get())) != remapper->end())
142                 key = string("{") + remap->second.c_str() + '}' + realname;
143             else
144                 key = string("{") + ns.get() + '}' + realname;
145         }
146         else
147             key = realname;
148         if (m_nested.find(key) != m_nested.end())
149             log->warn("load() skipping duplicate property set: %s", key.c_str());
150         else {
151             boost::shared_ptr<DOMPropertySet> newset(new DOMPropertySet());
152             newset->load(e,log,filter,remapper);
153             m_nested[key] = newset;
154             log->debug("added nested property set: %s", key.c_str());
155         }
156         e = static_cast<DOMElement*>(walker->nextSibling());
157     }
158     walker->release();
159 }
160
161 pair<bool,bool> DOMPropertySet::getBool(const char* name, const char* ns) const
162 {
163     map<string,pair<char*,const XMLCh*> >::const_iterator i;
164
165     if (ns)
166         i=m_map.find(string("{") + ns + '}' + name);
167     else
168         i=m_map.find(name);
169
170     if (i!=m_map.end())
171         return make_pair(true,(!strcmp(i->second.first,"true") || !strcmp(i->second.first,"1")));
172     else if (m_parent)
173         return m_parent->getBool(name,ns);
174     return make_pair(false,false);
175 }
176
177 pair<bool,const char*> DOMPropertySet::getString(const char* name, const char* ns) const
178 {
179     pair<bool,const char*> ret(false,nullptr);
180     map<string,pair<char*,const XMLCh*> >::const_iterator i;
181
182     if (ns)
183         i=m_map.find(string("{") + ns + '}' + name);
184     else
185         i=m_map.find(name);
186
187     if (i!=m_map.end())
188         return pair<bool,const char*>(true,i->second.first);
189     else if (m_parent)
190         return m_parent->getString(name,ns);
191     return pair<bool,const char*>(false,nullptr);
192 }
193
194 pair<bool,const XMLCh*> DOMPropertySet::getXMLString(const char* name, const char* ns) const
195 {
196     map<string,pair<char*,const XMLCh*> >::const_iterator i;
197
198     if (ns)
199         i=m_map.find(string("{") + ns + '}' + name);
200     else
201         i=m_map.find(name);
202
203     if (i!=m_map.end())
204         return make_pair(true,i->second.second);
205     else if (m_parent)
206         return m_parent->getXMLString(name,ns);
207     return pair<bool,const XMLCh*>(false,nullptr);
208 }
209
210 pair<bool,unsigned int> DOMPropertySet::getUnsignedInt(const char* name, const char* ns) const
211 {
212     map<string,pair<char*,const XMLCh*> >::const_iterator i;
213
214     if (ns)
215         i=m_map.find(string("{") + ns + '}' + name);
216     else
217         i=m_map.find(name);
218
219     if (i!=m_map.end())
220         return pair<bool,unsigned int>(true,strtol(i->second.first,nullptr,10));
221     else if (m_parent)
222         return m_parent->getUnsignedInt(name,ns);
223     return pair<bool,unsigned int>(false,0);
224 }
225
226 pair<bool,int> DOMPropertySet::getInt(const char* name, const char* ns) const
227 {
228     map<string,pair<char*,const XMLCh*> >::const_iterator i;
229
230     if (ns)
231         i=m_map.find(string("{") + ns + '}' + name);
232     else
233         i=m_map.find(name);
234
235     if (i!=m_map.end())
236         return pair<bool,int>(true,atoi(i->second.first));
237     else if (m_parent)
238         return m_parent->getInt(name,ns);
239     return pair<bool,int>(false,0);
240 }
241
242 void DOMPropertySet::getAll(std::map<std::string,const char*>& properties) const
243 {
244     if (m_parent)
245         m_parent->getAll(properties);
246     for (map< string,pair<char*,const XMLCh*> >::const_iterator i = m_map.begin(); i != m_map.end(); ++i)
247         properties[i->first] = i->second.first;
248 }
249
250 const PropertySet* DOMPropertySet::getPropertySet(const char* name, const char* ns) const
251 {
252     map<string,boost::shared_ptr<DOMPropertySet>>::const_iterator i;
253
254     if (ns)
255         i = m_nested.find(string("{") + ns + '}' + name);
256     else
257         i = m_nested.find(name);
258
259     return (i != m_nested.end()) ? i->second.get() : (m_parent ? m_parent->getPropertySet(name,ns) : nullptr);
260 }
261
262 bool DOMPropertySet::setProperty(const char* name, const char* val, const char* ns)
263 {
264     string propname = ns ? (string("{") + ns + "}" + name) : name;
265
266     // Erase existing property.
267     if (m_map.count(propname) > 0) {
268         XMLString::release(&m_map[propname].first);
269         m_map.erase(propname);
270     }
271
272     char* dup = XMLString::replicate(val);
273     auto_ptr_XMLCh widedup(val);
274     m_injected.push_back(widedup.get());
275     m_map[propname] = make_pair(dup, m_injected.back().c_str());
276
277     return true;
278 }