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