+/*\r
+ * Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * exceptions.cpp\r
+ * \r
+ * Exception classes\r
+ */\r
+ \r
+#include "internal.h"\r
+#include "exceptions.h"\r
+#include "XMLToolingConfig.h"\r
+#include "util/XMLConstants.h"\r
+#include "util/XMLHelper.h"\r
+\r
+#include <sstream>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+\r
+using namespace xmltooling;\r
+using namespace std;\r
+\r
+params::params(int count,...)\r
+{\r
+ va_list args;\r
+ va_start(args,count);\r
+ while (count--)\r
+ v.push_back(va_arg(args,char*));\r
+ va_end(args);\r
+}\r
+\r
+namedparams::namedparams(int count,...)\r
+{\r
+ count*=2;\r
+ va_list args;\r
+ va_start(args,count);\r
+ while (count--)\r
+ v.push_back(va_arg(args,char*));\r
+ va_end(args);\r
+}\r
+\r
+XMLToolingException::ExceptionFactoryMap XMLToolingException::m_factoryMap;\r
+\r
+XMLToolingException* XMLToolingException::getInstance(const char* exceptionClass)\r
+{\r
+ if (exceptionClass) {\r
+ ExceptionFactoryMap::const_iterator i=m_factoryMap.find(exceptionClass);\r
+ if (i!=m_factoryMap.end())\r
+ return (i->second)();\r
+ }\r
+ return new XMLToolingException();\r
+}\r
+\r
+XMLToolingException::XMLToolingException(const char* msg, const params& p)\r
+{\r
+ if (msg)\r
+ m_msg=msg;\r
+ addProperties(p);\r
+}\r
+\r
+XMLToolingException::XMLToolingException(const char* msg, const namedparams& p)\r
+{\r
+ if (msg)\r
+ m_msg=msg;\r
+ addProperties(p);\r
+}\r
+\r
+XMLToolingException::XMLToolingException(const std::string& msg, const params& p) : m_msg(msg)\r
+{\r
+ addProperties(p);\r
+}\r
+\r
+XMLToolingException::XMLToolingException(const std::string& msg, const namedparams& p) : m_msg(msg)\r
+{\r
+ addProperties(p);\r
+}\r
+\r
+void XMLToolingException::setMessage(const char* msg)\r
+{\r
+ if (msg)\r
+ m_msg=msg;\r
+ else\r
+ m_msg.erase();\r
+ m_processedmsg.erase();\r
+}\r
+\r
+inline const char* get_digit_character()\r
+{\r
+ static const char s_characters[19] = \r
+ {\r
+ '9'\r
+ , '8'\r
+ , '7'\r
+ , '6'\r
+ , '5'\r
+ , '4'\r
+ , '3'\r
+ , '2'\r
+ , '1'\r
+ , '0'\r
+ , '1'\r
+ , '2'\r
+ , '3'\r
+ , '4'\r
+ , '5'\r
+ , '6'\r
+ , '7'\r
+ , '8'\r
+ , '9'\r
+ };\r
+ static const char *s_mid = s_characters + 9;\r
+\r
+ return s_mid;\r
+}\r
+\r
+inline const char* unsigned_integer_to_string(char* buf, size_t cchBuf, int i)\r
+{\r
+ char* psz=buf + cchBuf - 1; // Set psz to last char\r
+ *psz = 0; // Set terminating null\r
+\r
+ do {\r
+ unsigned int lsd = i % 10; // Get least significant\r
+ // digit\r
+\r
+ i /= 10; // Prepare for next most\r
+ // significant digit\r
+\r
+ --psz; // Move back\r
+\r
+ *psz = get_digit_character()[lsd]; // Place the digit\r
+\r
+ } while(i!=0 && psz>buf);\r
+\r
+ return psz;\r
+}\r
+\r
+void XMLToolingException::addProperties(const params& p)\r
+{\r
+ m_processedmsg.erase();\r
+ int i=m_params.size()+1;\r
+ char buf[20];\r
+ const vector<const char*>& v=p.get();\r
+ for (vector<const char*>::const_iterator ci=v.begin(); ci!=v.end(); ci++) {\r
+ m_params[unsigned_integer_to_string(buf,sizeof(buf),i++)] = *ci;\r
+ }\r
+}\r
+ \r
+void XMLToolingException::addProperties(const namedparams& p)\r
+{\r
+ m_processedmsg.erase();\r
+ const vector<const char*>& v=p.get();\r
+ for (vector<const char*>::const_iterator ci=v.begin(); ci!=v.end(); ci++) {\r
+ m_params.erase(*ci);\r
+ m_params[*ci] = *(ci+1);\r
+ ci++; // advance past name to value, then loop will advance it again\r
+ }\r
+}\r
+\r
+const char* XMLToolingException::getProperty(unsigned int index) const\r
+{\r
+ char buf[20];\r
+ map<string,string>::const_iterator i=m_params.find(unsigned_integer_to_string(buf,sizeof(buf),index));\r
+ return (i==m_params.end()) ? NULL : i->second.c_str();\r
+}\r
+\r
+const char* XMLToolingException::getProperty(const char* name) const\r
+{\r
+ map<string,string>::const_iterator i=m_params.find(name);\r
+ return (i==m_params.end()) ? NULL : i->second.c_str();\r
+}\r
+\r
+const char* XMLToolingException::getMessage() const\r
+{\r
+ if (!m_processedmsg.empty())\r
+ return m_processedmsg.c_str();\r
+ else if (m_params.empty())\r
+ return m_msg.c_str();\r
+\r
+ static const char* legal="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_";\r
+\r
+ // Replace any parameters in the message.\r
+ string::size_type i=0,start=0;\r
+ while (start!=string::npos && start<m_msg.length() && (i=m_msg.find("$",start))!=string::npos) {\r
+ if (i>start)\r
+ m_processedmsg += m_msg.substr(start,i-start); // append everything in between\r
+ start=i+1; // move start to the beginning of the token name\r
+ i=m_msg.find_first_not_of(legal,start); // find token delimiter\r
+ if (i==start) { // append a non legal character\r
+ m_processedmsg+=m_msg[start++];\r
+ continue;\r
+ }\r
+ \r
+ // search for token in map\r
+ map<string,string>::const_iterator param=m_params.find(m_msg.substr(start,(i==string::npos) ? i : i-start));\r
+ if (param!=m_params.end()) {\r
+ m_processedmsg+=param->second;\r
+ start=i;\r
+ }\r
+ }\r
+ if (start!=string::npos && start<m_msg.length())\r
+ m_processedmsg += m_msg.substr(start,i); // append rest of string\r
+ return m_processedmsg.c_str();\r
+}\r
+\r
+string XMLToolingException::toString() const\r
+{\r
+ string xml=string("<exception xmlns=\"http://www.opensaml.org/xmltooling\" type=\"") + getClassName() + "\">";\r
+ const char* msg=getMessage();\r
+ if (msg)\r
+ xml=xml + "<message>" + msg + "</message>";\r
+ for (map<string,string>::const_iterator i=m_params.begin(); i!=m_params.end(); i++) {\r
+ xml=xml + "<param name=\"" + i->first + "\">" + i->second + "</param>";\r
+ }\r
+ xml+="</exception>";\r
+ return xml;\r
+}\r
+\r
+XMLToolingException* XMLToolingException::fromStream(std::istream& in)\r
+{\r
+ static const XMLCh exception[] = { chLatin_e, chLatin_x, chLatin_c, chLatin_e, chLatin_p, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull };\r
+ static const XMLCh message[] = { chLatin_m, chLatin_e, chLatin_s, chLatin_s, chLatin_a, chLatin_g, chLatin_e, chNull };\r
+ static const XMLCh name[] = { chLatin_n, chLatin_a, chLatin_m, chLatin_e, chNull };\r
+ static const XMLCh param[] = { chLatin_p, chLatin_a, chLatin_r, chLatin_a, chLatin_m, chNull };\r
+ static const XMLCh type[] = { chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };\r
+\r
+ DOMDocument* doc=XMLToolingInternalConfig::getInternalConfig().m_parserPool->parse(in);\r
+ \r
+ // Check root element.\r
+ const DOMElement* root=doc->getDocumentElement();\r
+ if (!XMLHelper::isNodeNamed(root,XMLConstants::XMLTOOLING_NS,exception)) {\r
+ doc->release();\r
+ throw XMLToolingException("Invalid root element on serialized exception.");\r
+ }\r
+ \r
+ auto_ptr_char classname(root->getAttributeNS(NULL,type));\r
+ auto_ptr<XMLToolingException> excep(XMLToolingException::getInstance(classname.get()));\r
+ \r
+ DOMElement* child=XMLHelper::getFirstChildElement(root,XMLConstants::XMLTOOLING_NS,message);\r
+ if (child && child->hasChildNodes()) {\r
+ auto_ptr_char m(child->getFirstChild()->getNodeValue());\r
+ excep->setMessage(m.get());\r
+ }\r
+ \r
+ child=XMLHelper::getFirstChildElement(root,XMLConstants::XMLTOOLING_NS,param);\r
+ while (child && child->hasChildNodes()) {\r
+ auto_ptr_char n(child->getAttributeNS(NULL,name));\r
+ char* v=toUTF8(child->getFirstChild()->getNodeValue());\r
+ if (n.get() && v)\r
+ excep->addProperty(n.get(), v);\r
+ XMLString::release(&v);\r
+ child=XMLHelper::getNextSiblingElement(root,XMLConstants::XMLTOOLING_NS,param);\r
+ }\r
+\r
+ doc->release();\r
+ return excep.release();\r
+}\r
+ \r
+XMLToolingException* XMLToolingException::fromString(const char* s)\r
+{\r
+ istringstream in(s);\r
+ return fromStream(in);\r
+}\r