2 Copyright (c) 2005-2006, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #ifdef ASDCP_USE_EXPAT
44 class ns_map : public std::map<std::string, XMLNamespace*>
50 ns_map::iterator ni = begin();
54 // fprintf(stderr, "deleting namespace %s:%s\n", ni->second->Prefix().c_str(), ni->second->Name().c_str());
62 Kumu::XMLElement::XMLElement(const char* name) : m_Namespace(0), m_NamespaceOwner(0)
67 Kumu::XMLElement::~XMLElement()
69 for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
72 if ( m_NamespaceOwner != 0 )
73 delete (ns_map*)m_NamespaceOwner;
78 Kumu::XMLElement::SetAttr(const char* name, const char* value)
84 m_AttrList.push_back(TmpVal);
89 Kumu::XMLElement::AddChild(const char* name)
91 XMLElement* tmpE = new XMLElement(name);
92 m_ChildList.push_back(tmpE);
98 Kumu::XMLElement::AddChildWithContent(const char* name, const std::string& value)
100 return AddChildWithContent(name, value.c_str());
105 Kumu::XMLElement::AppendBody(const std::string& value)
112 Kumu::XMLElement::AddChildWithContent(const char* name, const char* value)
116 XMLElement* tmpE = new XMLElement(name);
117 tmpE->m_Body = value;
118 m_ChildList.push_back(tmpE);
124 Kumu::XMLElement::AddChildWithPrefixedContent(const char* name, const char* prefix, const char* value)
126 XMLElement* tmpE = new XMLElement(name);
127 tmpE->m_Body = prefix;
128 tmpE->m_Body += value;
129 m_ChildList.push_back(tmpE);
135 Kumu::XMLElement::AddComment(const char* value)
144 Kumu::XMLElement::Render(std::string& outbuf) const
146 outbuf = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
147 RenderElement(outbuf, 0);
152 add_spacer(std::string& outbuf, i32_t depth)
160 Kumu::XMLElement::RenderElement(std::string& outbuf, ui32_t depth) const
162 add_spacer(outbuf, depth);
168 for ( Attr_i i = m_AttrList.begin(); i != m_AttrList.end(); i++ )
173 outbuf += (*i).value;
179 // body contents and children
180 if ( ! m_ChildList.empty() )
185 if ( m_Body.length() > 0 )
188 for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
189 (*i)->RenderElement(outbuf, depth + 1);
191 add_spacer(outbuf, depth);
193 else if ( m_Body.length() > 0 )
205 Kumu::XMLElement::HasName(const char* name) const
207 if ( name == 0 || *name == 0 )
210 return (m_Name == name);
215 Kumu::XMLElement::SetName(const char* name)
223 Kumu::XMLElement::GetAttrWithName(const char* name) const
225 for ( Attr_i i = m_AttrList.begin(); i != m_AttrList.end(); i++ )
227 if ( (*i).name == name )
228 return (*i).value.c_str();
236 Kumu::XMLElement::GetChildWithName(const char* name) const
238 for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
240 if ( (*i)->HasName(name) )
248 const Kumu::ElementList&
249 Kumu::XMLElement::GetChildrenWithName(const char* name, ElementList& outList) const
252 for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ )
254 if ( (*i)->HasName(name) )
255 outList.push_back(*i);
257 if ( ! (*i)->m_ChildList.empty() )
258 (*i)->GetChildrenWithName(name, outList);
264 //----------------------------------------------------------------------------------------------------
266 #ifdef ASDCP_USE_EXPAT
269 class ExpatParseContext
271 KM_NO_COPY_CONSTRUCT(ExpatParseContext);
275 std::stack<XMLElement*> Scope;
278 ExpatParseContext(XMLElement* root) : Root(root) {
279 Namespaces = new ns_map;
283 ~ExpatParseContext() {}
286 // expat wrapper functions
289 xph_start(void* p, const XML_Char* name, const XML_Char** attrs)
291 assert(p); assert(name); assert(attrs);
292 ExpatParseContext* Ctx = (ExpatParseContext*)p;
295 const char* ns_root = name;
296 const char* local_name = strchr(name, '|');
297 if ( local_name != 0 )
298 name = local_name + 1;
300 if ( Ctx->Scope.empty() )
302 Ctx->Scope.push(Ctx->Root);
306 Element = Ctx->Scope.top();
307 Ctx->Scope.push(Element->AddChild(name));
310 Element = Ctx->Scope.top();
311 Element->SetName(name);
315 if ( ns_root != name )
316 key.assign(ns_root, name - ns_root - 1);
318 ns_map::iterator ni = Ctx->Namespaces->find(key);
319 if ( ni != Ctx->Namespaces->end() )
320 Element->SetNamespace(ni->second);
323 for ( int i = 0; attrs[i] != 0; i += 2 )
325 if ( ( local_name = strchr(attrs[i], '|') ) == 0 )
326 local_name = attrs[i];
330 Element->SetAttr(local_name, attrs[i+1]);
336 xph_end(void* p, const XML_Char* name)
338 assert(p); assert(name);
339 ExpatParseContext* Ctx = (ExpatParseContext*)p;
345 xph_char(void* p, const XML_Char* data, int len)
347 assert(p); assert(data);
348 ExpatParseContext* Ctx = (ExpatParseContext*)p;
353 tmp_str.assign(data, len);
354 Ctx->Scope.top()->AppendBody(tmp_str);
360 xph_namespace_start(void* p, const XML_Char* ns_prefix, const XML_Char* ns_name)
362 assert(p); assert(ns_name);
363 ExpatParseContext* Ctx = (ExpatParseContext*)p;
365 if ( ns_prefix == 0 )
368 ns_map::iterator ni = Ctx->Namespaces->find(ns_name);
370 if ( ni != Ctx->Namespaces->end() )
372 if ( ni->second->Name() != std::string(ns_name) )
374 DefaultLogSink().Error("Duplicate prefix: %s\n", ns_prefix);
380 XMLNamespace* Namespace = new XMLNamespace(ns_prefix, ns_name);
381 Ctx->Namespaces->insert(ns_map::value_type(ns_name, Namespace));
387 Kumu::XMLElement::ParseString(const std::string& document)
389 XML_Parser Parser = XML_ParserCreateNS("UTF-8", '|');
393 DefaultLogSink().Error("Error allocating memory for XML parser.\n");
397 ExpatParseContext Ctx(this);
398 XML_SetUserData(Parser, (void*)&Ctx);
399 XML_SetElementHandler(Parser, xph_start, xph_end);
400 XML_SetCharacterDataHandler(Parser, xph_char);
401 XML_SetStartNamespaceDeclHandler(Parser, xph_namespace_start);
403 if ( ! XML_Parse(Parser, document.c_str(), document.size(), 1) )
405 XML_ParserFree(Parser);
406 DefaultLogSink().Error("XML Parse error on line %d: %s\n",
407 XML_GetCurrentLineNumber(Parser),
408 XML_ErrorString(XML_GetErrorCode(Parser)));
412 XML_ParserFree(Parser);
414 if ( ! Ctx.Namespaces->empty() )
415 m_NamespaceOwner = (void*)Ctx.Namespaces;
420 //------------------------------------------------------------------------------------------
422 struct xph_test_wrapper
427 xph_test_wrapper(XML_Parser p) : Parser(p), Status(false) {}
430 // expat wrapper functions, map callbacks to IASAXHandler
433 xph_test_start(void* p, const XML_Char* name, const XML_Char** attrs)
436 xph_test_wrapper* Wrapper = (xph_test_wrapper*)p;
438 Wrapper->Status = true;
439 XML_StopParser(Wrapper->Parser, false);
445 Kumu::StringIsXML(const char* document, ui32_t len)
451 len = strlen(document);
453 XML_Parser Parser = XML_ParserCreate("UTF-8");
457 DefaultLogSink().Error("Error allocating memory for XML parser.\n");
461 xph_test_wrapper Wrapper(Parser);
462 XML_SetUserData(Parser, (void*)&Wrapper);
463 XML_SetStartElementHandler(Parser, xph_test_start);
465 XML_Parse(Parser, document, len, 1);
466 XML_ParserFree(Parser);
467 return Wrapper.Status;
470 #else // no XML parser support
474 Kumu::XMLElement::ParseString(const std::string& document)
476 DefaultLogSink().Error("asdcplib compiled without XML parser support.\n");
482 Kumu::StringIsXML(const char* document, ui32_t len)
484 DefaultLogSink().Error("Kumu compiled without XML parser support.\n");