Reverting const accessor for class optional_property
[asdcplib.git] / src / KM_xml.cpp
index 64f0b740e64da3b160119ef630abc5af97a24e8c..68839a178e33b9f98fdd2d07d5beb4a41c3f6358 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2010, John Hurst
+Copyright (c) 2005-2015, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -61,13 +61,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 XERCES_CPP_NAMESPACE_USE 
 
-namespace Kumu {
-  void init_xml_dom();
-  typedef std::basic_string<XMLCh> XercesString;
-  bool UTF_8_to_XercesString(const std::string& in_str, XercesString& out_str);
-  bool UTF_8_to_XercesString(const char* in_str, XercesString& out_str);
-  bool XercesString_to_UTF_8(const XercesString& in_str, std::string& out_str);
-  bool XercesString_to_UTF_8(const XMLCh* in_str, std::string& out_str);
+extern "C"
+{
+  void kumu_init_xml_dom();
+  bool kumu_UTF_8_to_XercesString(const std::string& in_str, std::basic_string<XMLCh>& out_str);
+  bool kumu_UTF_8_to_XercesString_p(const char* in_str, std::basic_string<XMLCh>& out_str);
+  bool kumu_XercesString_to_UTF_8(const std::basic_string<XMLCh>& in_str, std::string& out_str);
+  bool kumu_XercesString_to_UTF_8_p(const XMLCh* in_str, std::string& out_str);
 }
 
 #endif
@@ -186,10 +186,10 @@ Kumu::XMLElement::AddComment(const char* value)
 
 //
 void
-Kumu::XMLElement::Render(std::string& outbuf) const
+Kumu::XMLElement::Render(std::string& outbuf, const bool& pretty) const
 {
   outbuf = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
-  RenderElement(outbuf, 0);
+  RenderElement(outbuf, 0, pretty);
 }
 
 //
@@ -202,15 +202,18 @@ add_spacer(std::string& outbuf, i32_t depth)
 
 //
 void
-Kumu::XMLElement::RenderElement(std::string& outbuf, ui32_t depth) const
+Kumu::XMLElement::RenderElement(std::string& outbuf, const ui32_t& depth, const bool& pretty) const
 {
-  add_spacer(outbuf, depth);
+  if ( pretty )
+    {
+      add_spacer(outbuf, depth);
+    }
 
   outbuf += "<";
   outbuf += m_Name;
 
   // render attributes
-  for ( Attr_i i = m_AttrList.begin(); i != m_AttrList.end(); i++ )
+  for ( Attr_i i = m_AttrList.begin(); i != m_AttrList.end(); ++i )
     {
       outbuf += " ";
       outbuf += (*i).name;
@@ -228,12 +231,19 @@ Kumu::XMLElement::RenderElement(std::string& outbuf, ui32_t depth) const
 
       // render body
       if ( m_Body.length() > 0 )
-       outbuf += m_Body;
+       {
+         outbuf += m_Body;
+       }
 
-      for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
-       (*i)->RenderElement(outbuf, depth + 1);
+      for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); ++i )
+       {
+         (*i)->RenderElement(outbuf, depth + 1, pretty);
+       }
 
-      add_spacer(outbuf, depth);
+      if ( pretty )
+       {
+         add_spacer(outbuf, depth);
+       }
     }
   else if ( m_Body.length() > 0 )
     {
@@ -389,6 +399,20 @@ Kumu::XMLElement::ParseString(const std::string& document)
   return ParseString(document.c_str(), document.size());
 }
 
+//
+bool
+Kumu::XMLElement::ParseFirstFromString(const ByteString& document)
+{
+  return ParseFirstFromString((const char*)document.RoData(), document.Length());
+}
+
+//
+bool
+Kumu::XMLElement::ParseFirstFromString(const std::string& document)
+{
+  return ParseFirstFromString(document.c_str(), document.size());
+}
+
 
 //----------------------------------------------------------------------------------------------------
 
@@ -515,6 +539,11 @@ xph_namespace_start(void* p, const XML_Char* ns_prefix, const XML_Char* ns_name)
 bool
 Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len)
 {
+  if ( doc_len == 0 )
+    {
+      return false;
+    }
+
   XML_Parser Parser = XML_ParserCreateNS("UTF-8", '|');
 
   if ( Parser == 0 )
@@ -531,55 +560,43 @@ Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len)
 
   if ( ! XML_Parse(Parser, document, doc_len, 1) )
     {
-      XML_ParserFree(Parser);
       DefaultLogSink().Error("XML Parse error on line %d: %s\n",
                             XML_GetCurrentLineNumber(Parser),
                             XML_ErrorString(XML_GetErrorCode(Parser)));
+      XML_ParserFree(Parser);
       return false;
     }
 
   XML_ParserFree(Parser);
 
   if ( ! Ctx.Namespaces->empty() )
-    m_NamespaceOwner = (void*)Ctx.Namespaces;
+    {
+      m_NamespaceOwner = (void*)Ctx.Namespaces;
+    }
 
   return true;
 }
 
-//------------------------------------------------------------------------------------------
-
-struct xph_test_wrapper
-{
-  XML_Parser Parser;
-  bool  Status;
-
-  xph_test_wrapper(XML_Parser p) : Parser(p), Status(false) {}
-};
-
-// expat wrapper functions, map callbacks to IASAXHandler
+// expat wrapper functions
 // 
 static void
-xph_test_start(void* p, const XML_Char* name, const XML_Char** attrs)
+xph_start_one_shot(void* p, const XML_Char* name, const XML_Char** attrs)
 {
-  assert(p);
-  xph_test_wrapper* Wrapper = (xph_test_wrapper*)p;
-
-  Wrapper->Status = true;
-  XML_StopParser(Wrapper->Parser, false);
+  xph_start(p, name, attrs);
+  XML_Parser parser = (XML_Parser)p;
+  XML_StopParser(parser, false);
 }
 
-
 //
 bool
-Kumu::StringIsXML(const char* document, ui32_t len)
+Kumu::XMLElement::ParseFirstFromString(const char* document, ui32_t doc_len)
 {
-  if ( document == 0 )
-    return false;
-
-  if ( len == 0 )
-    len = strlen(document);
+  if ( doc_len == 0 )
+    {
+      return false;
+    }
 
-  XML_Parser Parser = XML_ParserCreate("UTF-8");
+  XML_Parser Parser = XML_ParserCreateNS("UTF-8", '|');
 
   if ( Parser == 0 )
     {
@@ -587,15 +604,30 @@ Kumu::StringIsXML(const char* document, ui32_t len)
       return false;
     }
 
-  xph_test_wrapper Wrapper(Parser);
-  XML_SetUserData(Parser, (void*)&Wrapper);
-  XML_SetStartElementHandler(Parser, xph_test_start);
+  ExpatParseContext Ctx(this);
+  XML_SetUserData(Parser, (void*)&Ctx);
+  XML_SetElementHandler(Parser, xph_start_one_shot, xph_end);
+  XML_SetCharacterDataHandler(Parser, xph_char);
+  XML_SetStartNamespaceDeclHandler(Parser, xph_namespace_start);
+
+  if ( ! XML_Parse(Parser, document, doc_len, 1) )
+    {
+      XML_ParserFree(Parser);
+      return false;
+    }
 
-  XML_Parse(Parser, document, len, 1);
   XML_ParserFree(Parser);
-  return Wrapper.Status;
+
+  if ( ! Ctx.Namespaces->empty() )
+    {
+      m_NamespaceOwner = (void*)Ctx.Namespaces;
+    }
+
+  return true;
 }
 
+
+
 #endif
 
 //----------------------------------------------------------------------------------------------------
@@ -616,7 +648,7 @@ static const XMLCh sg_label_UTF_8[] = { chLatin_U, chLatin_T, chLatin_F,
 
 //
 void
-Kumu::init_xml_dom()
+kumu_init_xml_dom()
 {
   if ( ! sg_xml_init )
     {
@@ -656,13 +688,13 @@ Kumu::init_xml_dom()
 
 //
 bool
-Kumu::XercesString_to_UTF_8(const Kumu::XercesString& in_str, std::string& out_str) {
-  return XercesString_to_UTF_8(in_str.c_str(), out_str);
+kumu_XercesString_to_UTF_8(const std::basic_string<XMLCh>& in_str, std::string& out_str) {
+  return kumu_XercesString_to_UTF_8_p(in_str.c_str(), out_str);
 }
 
 //
 bool
-Kumu::XercesString_to_UTF_8(const XMLCh* in_str, std::string& out_str)
+kumu_XercesString_to_UTF_8_p(const XMLCh* in_str, std::string& out_str)
 {
   assert(in_str);
   assert(sg_xml_init);
@@ -699,13 +731,13 @@ Kumu::XercesString_to_UTF_8(const XMLCh* in_str, std::string& out_str)
 
 //
 bool
-Kumu::UTF_8_to_XercesString(const std::string& in_str, Kumu::XercesString& out_str) {
-  return UTF_8_to_XercesString(in_str.c_str(), out_str);
+kumu_UTF_8_to_XercesString(const std::string& in_str, std::basic_string<XMLCh>& out_str) {
+  return kumu_UTF_8_to_XercesString_p(in_str.c_str(), out_str);
 }
 
 //
 bool
-Kumu::UTF_8_to_XercesString(const char* in_str, Kumu::XercesString& out_str)
+kumu_UTF_8_to_XercesString_p(const char* in_str, std::basic_string<XMLCh>& out_str)
 {
   assert(in_str);
   assert(sg_xml_init);
@@ -787,7 +819,7 @@ public:
        ns_prefix = "";
       }
 
-    ns_map::iterator ni = m_Namespaces->find(ns_name);
+    ns_map::iterator ni = m_Namespaces->find(ns_prefix);
 
     if  ( ni != m_Namespaces->end() )
       {
@@ -813,7 +845,7 @@ public:
     assert(x_name);
     std::string tx_name;
 
-    if ( ! XercesString_to_UTF_8(x_name, tx_name) )
+    if ( ! kumu_XercesString_to_UTF_8(x_name, tx_name) )
       m_HasEncodeErrors = true;
 
     const char* name = tx_name.c_str();
@@ -843,10 +875,10 @@ public:
     for ( ui32_t i = 0; i < a_len; i++)
       {
        std::string aname, value;
-       if ( ! XercesString_to_UTF_8(attributes.getName(i), aname) )
+       if ( ! kumu_XercesString_to_UTF_8(attributes.getName(i), aname) )
          m_HasEncodeErrors = true;
 
-       if ( ! XercesString_to_UTF_8(attributes.getValue(i), value) )
+       if ( ! kumu_XercesString_to_UTF_8(attributes.getValue(i), value) )
          m_HasEncodeErrors = true;
 
        const char* x_aname = aname.c_str();
@@ -877,12 +909,16 @@ public:
     m_Scope.pop();
   }
 
+#if XERCES_VERSION_MAJOR < 3
   void characters(const XMLCh *const chars, const unsigned int length)
+#else
+  void characters(const XMLCh* const chars, const XMLSize_t length)
+#endif
   {
     if ( length > 0 )
       {
        std::string tmp;
-       if ( ! XercesString_to_UTF_8(chars, tmp) )
+       if ( ! kumu_XercesString_to_UTF_8(chars, tmp) )
          m_HasEncodeErrors = true;
 
        m_Scope.top()->AppendBody(tmp);
@@ -895,9 +931,11 @@ bool
 Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len)
 {
   if ( doc_len == 0 )
-    return false;
+    {
+      return false;
+    }
 
-  init_xml_dom();
+  kumu_init_xml_dom();
 
   int errorCount = 0;
   SAXParser* parser = new SAXParser();
@@ -948,37 +986,56 @@ Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len)
 
 //
 bool
-Kumu::StringIsXML(const char* document, ui32_t len)
+Kumu::XMLElement::ParseFirstFromString(const char* document, ui32_t doc_len)
 {
-  if ( document == 0 || *document == 0 )
-    return false;
+  if ( doc_len == 0 )
+    {
+      return false;
+    }
 
-  init_xml_dom();
+  kumu_init_xml_dom();
+  
+  int errorCount = 0;
+  SAXParser* parser = new SAXParser();
 
-  if ( len == 0 )
-    len = strlen(document);
+  parser->setValidationScheme(SAXParser::Val_Always);
+  parser->setDoNamespaces(true);    // optional
 
-  SAXParser parser;
+  MyTreeHandler* docHandler = new MyTreeHandler(this);
+  parser->setDocumentHandler(docHandler);
+  parser->setErrorHandler(docHandler);
   XMLPScanToken token;
-  bool status = false;
 
   try
     {
       MemBufInputSource xmlSource(reinterpret_cast<const XMLByte*>(document),
-                                 static_cast<const unsigned int>(len),
+                                 static_cast<const unsigned int>(doc_len),
                                  "pidc_rules_file");
 
-      if ( parser.parseFirst(xmlSource, token) )
+      if ( ! parser->parseFirst(xmlSource, token) )
+       {
+         ++errorCount;
+       }
+
+      if ( ! parser->parseNext(token) )
        {
-         if ( parser.parseNext(token) )
-           status = true;
+         ++errorCount;
        }
     }
   catch (...)
     {
+      errorCount++;
     }
   
-  return status;
+  if ( errorCount == 0 )
+    {
+      m_NamespaceOwner = (void*)docHandler->TakeNamespaceMap();
+    }
+
+  delete parser;
+  delete docHandler;
+
+  return errorCount > 0 ? false : true;
 }
 
 
@@ -990,15 +1047,14 @@ Kumu::StringIsXML(const char* document, ui32_t len)
 
 //
 bool
-Kumu::XMLElement::ParseString(const std::string& document)
+Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len)
 {
   DefaultLogSink().Error("Kumu compiled without XML parser support.\n");
   return false;
 }
 
-//
 bool
-Kumu::StringIsXML(const char* document, ui32_t len)
+Kumu::XMLElement::ParseFirstFromString(const char* document, ui32_t doc_len)
 {
   DefaultLogSink().Error("Kumu compiled without XML parser support.\n");
   return false;
@@ -1007,6 +1063,50 @@ Kumu::StringIsXML(const char* document, ui32_t len)
 #endif
 
 
+//----------------------------------------------------------------------------------------------------
+
+//
+bool
+Kumu::GetXMLDocType(const ByteString& buf, std::string& ns_prefix, std::string& type_name, std::string& namespace_name,
+                   AttributeList& doc_attr_list)
+{
+  return GetXMLDocType(buf.RoData(), buf.Length(), ns_prefix, type_name, namespace_name, doc_attr_list);
+}
+
+//
+bool
+Kumu::GetXMLDocType(const std::string& buf, std::string& ns_prefix, std::string& type_name, std::string& namespace_name,
+                   AttributeList& doc_attr_list)
+{
+  return GetXMLDocType((const byte_t*)buf.c_str(), buf.size(), ns_prefix, type_name, namespace_name, doc_attr_list);
+}
+
+//
+bool
+Kumu::GetXMLDocType(const byte_t* buf, ui32_t buf_len, std::string& ns_prefix, std::string& type_name, std::string& namespace_name,
+                   AttributeList& doc_attr_list)
+{
+  XMLElement tmp_element("tmp");
+
+  if ( ! tmp_element.ParseFirstFromString((const char*)buf, buf_len) )
+    {
+      return false;
+    }
+
+  const XMLNamespace* ns = tmp_element.Namespace();
+
+  if ( ns != 0 )
+    {
+      ns_prefix = ns->Prefix();
+      namespace_name = ns->Name();
+    }
+
+  type_name = tmp_element.GetName();
+  doc_attr_list = tmp_element.GetAttributes();
+  return true;
+}
+
+
 //
 // end KM_xml.cpp
 //