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