XMLParser.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * This source file is part of libRocket, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://www.librocket.com
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. *
  26. */
  27. #include "precompiled.h"
  28. #include "../../Include/Rocket/Core/XMLParser.h"
  29. #include "DocumentHeader.h"
  30. #include "../../Include/Rocket/Core/Log.h"
  31. #include "../../Include/Rocket/Core/XMLNodeHandler.h"
  32. namespace Rocket {
  33. namespace Core {
  34. typedef UnorderedMap< String, XMLNodeHandler* > NodeHandlers;
  35. static NodeHandlers node_handlers;
  36. static XMLNodeHandler* default_node_handler = NULL;
  37. XMLParser::XMLParser(Element* root)
  38. {
  39. RegisterCDATATag("script");
  40. // Add the first frame.
  41. ParseFrame frame;
  42. frame.node_handler = NULL;
  43. frame.child_handler = NULL;
  44. frame.element = root;
  45. frame.tag = "";
  46. stack.push(frame);
  47. active_handler = NULL;
  48. header = new DocumentHeader();
  49. }
  50. XMLParser::~XMLParser()
  51. {
  52. delete header;
  53. }
  54. // Registers a custom node handler to be used to a given tag.
  55. XMLNodeHandler* XMLParser::RegisterNodeHandler(const String& _tag, XMLNodeHandler* handler)
  56. {
  57. String tag = ToLower(_tag);
  58. // Check for a default node registration.
  59. if (tag.empty())
  60. {
  61. if (default_node_handler != NULL)
  62. default_node_handler->RemoveReference();
  63. default_node_handler = handler;
  64. default_node_handler->AddReference();
  65. return default_node_handler;
  66. }
  67. NodeHandlers::iterator i = node_handlers.find(tag);
  68. if (i != node_handlers.end())
  69. (*i).second->RemoveReference();
  70. node_handlers[tag] = handler;
  71. handler->AddReference();
  72. return handler;
  73. }
  74. // Releases all registered node handlers. This is called internally.
  75. void XMLParser::ReleaseHandlers()
  76. {
  77. if (default_node_handler != NULL)
  78. {
  79. default_node_handler->RemoveReference();
  80. default_node_handler = NULL;
  81. }
  82. for (NodeHandlers::iterator i = node_handlers.begin(); i != node_handlers.end(); ++i)
  83. (*i).second->RemoveReference();
  84. node_handlers.clear();
  85. }
  86. DocumentHeader* XMLParser::GetDocumentHeader()
  87. {
  88. return header;
  89. }
  90. const URL& XMLParser::GetSourceURL() const
  91. {
  92. return xml_source->GetSourceURL();
  93. }
  94. // Pushes the default element handler onto the parse stack.
  95. void XMLParser::PushDefaultHandler()
  96. {
  97. active_handler = default_node_handler;
  98. }
  99. bool XMLParser::PushHandler(const String& tag)
  100. {
  101. NodeHandlers::iterator i = node_handlers.find(ToLower(tag));
  102. if (i == node_handlers.end())
  103. return false;
  104. active_handler = (*i).second;
  105. return true;
  106. }
  107. /// Access the current parse frame
  108. const XMLParser::ParseFrame* XMLParser::GetParseFrame() const
  109. {
  110. return &stack.top();
  111. }
  112. /// Called when the parser finds the beginning of an element tag.
  113. void XMLParser::HandleElementStart(const String& _name, const XMLAttributes& _attributes)
  114. {
  115. String name = ToLower(_name);
  116. XMLAttributes attributes;
  117. for (auto& [key, variant] : _attributes)
  118. {
  119. attributes.emplace(key, variant.Get<String>());
  120. }
  121. // Check for a specific handler that will override the child handler.
  122. NodeHandlers::iterator itr = node_handlers.find(name);
  123. if (itr != node_handlers.end())
  124. active_handler = (*itr).second;
  125. // Store the current active handler, so we can use it through this function (as active handler may change)
  126. XMLNodeHandler* node_handler = active_handler;
  127. Element* element = NULL;
  128. // Get the handler to handle the open tag
  129. if (node_handler)
  130. {
  131. element = node_handler->ElementStart(this, name, attributes);
  132. }
  133. // Push onto the stack
  134. ParseFrame frame;
  135. frame.node_handler = node_handler;
  136. frame.child_handler = active_handler;
  137. frame.element = element != NULL ? element : stack.top().element;
  138. frame.tag = name;
  139. stack.push(frame);
  140. }
  141. /// Called when the parser finds the end of an element tag.
  142. void XMLParser::HandleElementEnd(const String& _name)
  143. {
  144. String name = ToLower(_name);
  145. // Copy the top of the stack
  146. ParseFrame frame = stack.top();
  147. // Pop the frame
  148. stack.pop();
  149. // Restore active handler to the previous frame's child handler
  150. active_handler = stack.top().child_handler;
  151. // Check frame names
  152. if (name != frame.tag)
  153. {
  154. Log::Message(Log::LT_ERROR, "Closing tag '%s' mismatched on %s:%d was expecting '%s'.", name.c_str(), GetSourceURL().GetURL().c_str(), GetLineNumber(), frame.tag.c_str());
  155. }
  156. // Call element end handler
  157. if (frame.node_handler)
  158. {
  159. frame.node_handler->ElementEnd(this, name);
  160. }
  161. }
  162. /// Called when the parser encounters data.
  163. void XMLParser::HandleData(const String& data)
  164. {
  165. if (stack.top().node_handler)
  166. stack.top().node_handler->ElementData(this, data);
  167. }
  168. }
  169. }