Set fourth file version digit to signify rebuild.
[shibboleth/cpp-xmltooling.git] / xmltooling / exceptions.cpp
index 56ce6d3..6ff78ca 100644 (file)
@@ -1,17 +1,21 @@
-/*
- *  Copyright 2001-2007 Internet2
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ * UCAID licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the
+ * License at
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
  */
 
 /**
 #include "internal.h"
 #include "exceptions.h"
 #include "XMLToolingConfig.h"
+#include "util/URLEncoder.h"
 #include "util/XMLConstants.h"
 #include "util/XMLHelper.h"
 
 #include <stdarg.h>
+#include <memory>
 #include <sstream>
+#include <boost/lexical_cast.hpp>
 #include <xercesc/util/XMLUniDefs.hpp>
 
 using namespace xmltooling;
+using namespace xercesc;
+using namespace boost;
 using namespace std;
 using xmlconstants::XMLTOOLING_NS;
 
@@ -98,89 +107,46 @@ void XMLToolingException::setMessage(const char* msg)
     m_processedmsg.erase();
 }
 
-inline const char* get_digit_character()
-{
-    static const char  s_characters[19] = 
-    {
-            '9'
-        ,   '8'
-        ,   '7'
-        ,   '6'
-        ,   '5'
-        ,   '4'
-        ,   '3'
-        ,   '2'
-        ,   '1'
-        ,   '0'
-        ,   '1'
-        ,   '2'
-        ,   '3'
-        ,   '4'
-        ,   '5'
-        ,   '6'
-        ,   '7'
-        ,   '8'
-        ,   '9'
-    };
-    static const char  *s_mid  =   s_characters + 9;
-
-    return s_mid;
-}
-
-inline const char* unsigned_integer_to_string(char* buf, size_t cchBuf, int i)
-{
-    char* psz=buf + cchBuf - 1;     // Set psz to last char
-    *psz = 0;                       // Set terminating null
-
-    do {
-        unsigned int lsd = i % 10;  // Get least significant
-                                    // digit
-
-        i /= 10;                    // Prepare for next most
-                                    // significant digit
-
-        --psz;                      // Move back
-
-        *psz = get_digit_character()[lsd]; // Place the digit
-
-    } while(i!=0 && psz>buf);
-
-    return psz;
-}
-
 void XMLToolingException::addProperties(const params& p)
 {
     m_processedmsg.erase();
-    int i=m_params.size()+1;
-    char buf[20];
+    map<string,string>::size_type i = m_params.size() + 1;
     const vector<const char*>& v=p.get();
-    for (vector<const char*>::const_iterator ci=v.begin(); ci!=v.end(); ci++) {
-        m_params[unsigned_integer_to_string(buf,sizeof(buf),i++)] = *ci;
+    for (vector<const char*>::const_iterator ci = v.begin(); ci != v.end(); ++ci) {
+        try {
+            m_params[lexical_cast<string>(i++)] = *ci;
+        }
+        catch (bad_lexical_cast&) {
+        }
     }
 }
         
 void XMLToolingException::addProperties(const namedparams& p)
 {
     m_processedmsg.erase();
-    const vector<const char*>& v=p.get();
-    for (vector<const char*>::const_iterator ci=v.begin(); ci!=v.end(); ci++) {
+    const vector<const char*>& v = p.get();
+    for (vector<const char*>::const_iterator ci = v.begin(); ci != v.end(); ++ci) {
         m_params.erase(*ci);
         m_params[*ci] = *(ci+1);
-        ci++;   // advance past name to value, then loop will advance it again
+        ++ci;   // advance past name to value, then loop will advance it again
     }
 }
 
 const char* XMLToolingException::getProperty(unsigned int index) const
 {
-    char buf[20];
-    map<string,string>::const_iterator i=m_params.find(unsigned_integer_to_string(buf,sizeof(buf),index));
-    return (i==m_params.end()) ? NULL : i->second.c_str();
+    try {
+        map<string,string>::const_iterator i = m_params.find(lexical_cast<string>(index));
+        return (i==m_params.end()) ? nullptr : i->second.c_str();
+    }
+    catch (bad_lexical_cast&) {
+        return nullptr;
+    }
 }
 
 const char* XMLToolingException::getProperty(const char* name) const
 {
-    map<string,string>::const_iterator i=m_params.find(name);
-    return (i==m_params.end()) ? NULL : i->second.c_str();
+    map<string,string>::const_iterator i = m_params.find(name);
+    return (i==m_params.end()) ? nullptr : i->second.c_str();
 }
 
 const char* XMLToolingException::getMessage() const
@@ -216,26 +182,64 @@ const char* XMLToolingException::getMessage() const
     return m_processedmsg.c_str();
 }
 
+void xml_encode(string& s, const char* pre, const char* start, const char* post)
+{
+    s += pre;
+    size_t pos;
+    while (start && *start) {
+        pos = strcspn(start, "\"<>&");
+        if (pos > 0) {
+            s.append(start, pos);
+            start += pos;
+        }
+        else {
+            switch (*start) {
+                case '\'':  s += "&apos;";     break;
+                case '<':   s += "&lt;";       break;
+                case '>':   s += "&gt;";       break;
+                case '&':   s += "&amp;";      break;
+                default:    s += *start;
+            }
+            start++;
+        }
+    }
+    s += post;
+}
+
 string XMLToolingException::toString() const
 {
-    string xml=string("<exception xmlns=\"http://www.opensaml.org/xmltooling\" type=\"") + getClassName() + "\">";
+    string xml=string("<exception xmlns='http://www.opensaml.org/xmltooling' type='") + getClassName() + "'>";
     const char* msg=getMessage();
     if (msg)
-        xml=xml + "<message>" + msg + "</message>";
-    for (map<string,string>::const_iterator i=m_params.begin(); i!=m_params.end(); i++) {
-        xml=xml + "<param name=\"" + i->first + "\">" + i->second + "</param>";
+        xml_encode(xml, "<message>", msg, "</message>");
+    const URLEncoder* encoder = XMLToolingConfig::getConfig().getURLEncoder();
+    for (map<string,string>::const_iterator i = m_params.begin(); i != m_params.end(); ++i) {
+        xml_encode(xml, "<param name='", i->first.c_str(), "'");
+        xml_encode(xml, ">", encoder->encode(i->second.c_str()).c_str(), "</param>");
     }
     xml+="</exception>";
     return xml;
 }
 
+string XMLToolingException::toQueryString() const
+{
+    string q;
+    const URLEncoder* enc = XMLToolingConfig::getConfig().getURLEncoder();
+    for (map<string,string>::const_iterator i = m_params.begin(); i != m_params.end(); ++i) {
+        if (!q.empty())
+            q += '&';
+        q = q + i->first + '=' + enc->encode(i->second.c_str());
+    }
+    return q;
+}
+
 XMLToolingException* XMLToolingException::fromStream(std::istream& in)
 {
-    static const XMLCh exception[] = { chLatin_e, chLatin_x, chLatin_c, chLatin_e, chLatin_p, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull };
-    static const XMLCh message[] = { chLatin_m, chLatin_e, chLatin_s, chLatin_s, chLatin_a, chLatin_g, chLatin_e, chNull };
-    static const XMLCh name[] = { chLatin_n, chLatin_a, chLatin_m, chLatin_e, chNull };
-    static const XMLCh param[] = { chLatin_p, chLatin_a, chLatin_r, chLatin_a, chLatin_m, chNull };
-    static const XMLCh type[] = { chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
+    static const XMLCh exception[] =    UNICODE_LITERAL_9(e,x,c,e,p,t,i,o,n);
+    static const XMLCh message[] =      UNICODE_LITERAL_7(m,e,s,s,a,g,e);
+    static const XMLCh name[] =         UNICODE_LITERAL_4(n,a,m,e);
+    static const XMLCh param[] =        UNICODE_LITERAL_5(p,a,r,a,m);
+    static const XMLCh type[] =         UNICODE_LITERAL_4(t,y,p,e);
 
     DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);
     
@@ -246,7 +250,7 @@ XMLToolingException* XMLToolingException::fromStream(std::istream& in)
         throw XMLToolingException("Invalid root element on serialized exception.");
     }
     
-    auto_ptr_char classname(root->getAttributeNS(NULL,type));
+    auto_ptr_char classname(root->getAttributeNS(nullptr,type));
     auto_ptr<XMLToolingException> excep(XMLToolingException::getInstance(classname.get()));
     
     DOMElement* child=XMLHelper::getFirstChildElement(root,XMLTOOLING_NS,message);
@@ -255,14 +259,17 @@ XMLToolingException* XMLToolingException::fromStream(std::istream& in)
         excep->setMessage(m.get());
     }
     
+    const URLEncoder* encoder = XMLToolingConfig::getConfig().getURLEncoder();
     child=XMLHelper::getFirstChildElement(root,XMLTOOLING_NS,param);
     while (child && child->hasChildNodes()) {
-        auto_ptr_char n(child->getAttributeNS(NULL,name));
-        char* v=toUTF8(child->getFirstChild()->getNodeValue());
-        if (n.get() && v)
-            excep->addProperty(n.get(), v);
-        XMLString::release(&v);
-        child=XMLHelper::getNextSiblingElement(root,XMLTOOLING_NS,param);
+        auto_ptr_char n(child->getAttributeNS(nullptr,name));
+        char* encoded = XMLString::transcode(child->getFirstChild()->getNodeValue());
+        if (n.get() && encoded) {
+            encoder->decode(encoded);
+            excep->addProperty(n.get(), encoded);
+        }
+        XMLString::release(&encoded);
+        child=XMLHelper::getNextSiblingElement(child,XMLTOOLING_NS,param);
     }
 
     doc->release();