XMLParseTools.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include "XMLParseTools.h"
  2. #include "../../Include/RmlUi/Core/ElementDocument.h"
  3. #include "../../Include/RmlUi/Core/StreamMemory.h"
  4. #include "../../Include/RmlUi/Core/StringUtilities.h"
  5. #include "../../Include/RmlUi/Core/Types.h"
  6. #include "Template.h"
  7. #include "TemplateCache.h"
  8. #include <ctype.h>
  9. #include <string.h>
  10. namespace Rml {
  11. const char* XMLParseTools::FindTag(const char* tag, const char* string, bool closing_tag)
  12. {
  13. const size_t length = strlen(tag);
  14. const char* ptr = string;
  15. bool found_closing = false;
  16. while (*ptr)
  17. {
  18. // Check if the first character matches
  19. if (tolower((*ptr)) == tag[0])
  20. {
  21. // If it does, check the whole word
  22. if (StringUtilities::StringCompareCaseInsensitive(StringView(ptr, ptr + length), StringView(tag, tag + length)))
  23. {
  24. // Check for opening <, loop back in the string skipping white space and forward slashes if
  25. // we're looking for the closing tag
  26. const char* tag_start = ptr - 1;
  27. while (tag_start > string && (StringUtilities::IsWhitespace(*tag_start) || *tag_start == '/'))
  28. {
  29. if (*tag_start == '/')
  30. found_closing = true;
  31. tag_start--;
  32. }
  33. // If the character we're looking at is a <, and found closing matches closing tag,
  34. // its the tag we're looking for
  35. if (*tag_start == '<' && found_closing == closing_tag)
  36. return tag_start;
  37. // Otherwise, keep looking
  38. }
  39. }
  40. ptr++;
  41. }
  42. return nullptr;
  43. }
  44. bool XMLParseTools::ReadAttribute(const char*& string, String& name, String& value)
  45. {
  46. const char* ptr = string;
  47. name = "";
  48. value = "";
  49. // Skip whitespace
  50. while (StringUtilities::IsWhitespace(*ptr))
  51. ptr++;
  52. // Look for the end of the attribute name
  53. bool found_whitespace = false;
  54. while (*ptr != '=' && *ptr != '>' && (!found_whitespace || StringUtilities::IsWhitespace(*ptr)))
  55. {
  56. if (StringUtilities::IsWhitespace(*ptr))
  57. found_whitespace = true;
  58. else
  59. name += *ptr;
  60. ptr++;
  61. }
  62. if (*ptr == '>')
  63. return false;
  64. // If we stopped on an equals, parse the value
  65. if (*ptr == '=')
  66. {
  67. // Skip over white space, ='s and quotes
  68. bool quoted = false;
  69. while (StringUtilities::IsWhitespace(*ptr) || *ptr == '\'' || *ptr == '"' || *ptr == '=')
  70. {
  71. if (*ptr == '\'' || *ptr == '"')
  72. quoted = true;
  73. ptr++;
  74. }
  75. if (*ptr == '>')
  76. return false;
  77. // Store the value
  78. while (*ptr != '\'' && *ptr != '"' && *ptr != '>' && (*ptr != ' ' || quoted))
  79. {
  80. value += *ptr++;
  81. }
  82. if (*ptr == '>')
  83. return false;
  84. // Advance passed the quote
  85. if (quoted)
  86. ptr++;
  87. }
  88. else
  89. {
  90. ptr--;
  91. }
  92. // Update the string pointer
  93. string = ptr;
  94. return true;
  95. }
  96. Element* XMLParseTools::ParseTemplate(Element* element, const String& template_name)
  97. {
  98. // Load the template, and parse it
  99. Template* parse_template = TemplateCache::GetTemplate(template_name);
  100. if (!parse_template)
  101. {
  102. Log::ParseError(element->GetOwnerDocument()->GetSourceURL(), -1, "Failed to find template '%s'.", template_name.c_str());
  103. return element;
  104. }
  105. return parse_template->ParseTemplate(element);
  106. }
  107. const char* XMLParseTools::ParseDataBrackets(bool& inside_brackets, bool& inside_string, char c, char previous)
  108. {
  109. if (inside_brackets)
  110. {
  111. if (c == '\'')
  112. inside_string = !inside_string;
  113. if (!inside_string)
  114. {
  115. if (c == '}' && previous == '}')
  116. inside_brackets = false;
  117. else if (c == '{' && previous == '{')
  118. return "Nested double curly brackets are illegal.";
  119. else if (previous == '}' && c != '}' && c != '\'')
  120. return "Single closing curly bracket encountered, use double curly brackets to close an expression.";
  121. else if (previous == '/' && c == '>')
  122. return "Closing double curly brackets not found, XML end node encountered first.";
  123. else if (previous == '<' && c == '/')
  124. return "Closing double curly brackets not found, XML end node encountered first.";
  125. }
  126. }
  127. else
  128. {
  129. if (c == '{' && previous == '{')
  130. {
  131. inside_brackets = true;
  132. }
  133. else if (c == '}' && previous == '}')
  134. {
  135. return "Closing double curly brackets encountered outside an expression.";
  136. }
  137. }
  138. return nullptr;
  139. }
  140. } // namespace Rml