1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 file Copyright.txt or https://cmake.org/licensing for details. */ 3 #pragma once 4 5 #include "cmConfigure.h" // IWYU pragma: keep 6 7 #include <chrono> 8 #include <cstddef> // IWYU pragma: keep 9 #include <ctime> 10 #include <ostream> 11 #include <stack> 12 #include <string> 13 #include <vector> 14 15 #include "cmXMLSafe.h" 16 17 class cmXMLWriter 18 { 19 public: 20 cmXMLWriter(std::ostream& output, std::size_t level = 0); 21 ~cmXMLWriter(); 22 23 cmXMLWriter(cmXMLWriter const&) = delete; 24 cmXMLWriter& operator=(cmXMLWriter const&) = delete; 25 26 void StartDocument(const char* encoding = "UTF-8"); 27 void EndDocument(); 28 29 void StartElement(std::string const& name); 30 void EndElement(); 31 32 void BreakAttributes(); 33 34 template <typename T> Attribute(const char * name,T const & value)35 void Attribute(const char* name, T const& value) 36 { 37 this->PreAttribute(); 38 this->Output << name << "=\"" << SafeAttribute(value) << '"'; 39 } 40 41 void Element(const char* name); 42 43 template <typename T> Element(std::string const & name,T const & value)44 void Element(std::string const& name, T const& value) 45 { 46 this->StartElement(name); 47 this->Content(value); 48 this->EndElement(); 49 } 50 51 template <typename T> Content(T const & content)52 void Content(T const& content) 53 { 54 this->PreContent(); 55 this->Output << SafeContent(content); 56 } 57 58 void Comment(const char* comment); 59 60 void CData(std::string const& data); 61 62 void Doctype(const char* doctype); 63 64 void ProcessingInstruction(const char* target, const char* data); 65 66 void FragmentFile(const char* fname); 67 68 void SetIndentationElement(std::string const& element); 69 70 private: 71 void ConditionalLineBreak(bool condition); 72 73 void PreAttribute(); 74 void PreContent(); 75 76 void CloseStartElement(); 77 SafeAttribute(const char * value)78 static cmXMLSafe SafeAttribute(const char* value) { return { value }; } 79 SafeAttribute(std::string const & value)80 static cmXMLSafe SafeAttribute(std::string const& value) 81 { 82 return { value }; 83 } 84 85 template <typename T> SafeAttribute(T value)86 static T SafeAttribute(T value) 87 { 88 return value; 89 } 90 SafeContent(const char * value)91 static cmXMLSafe SafeContent(const char* value) 92 { 93 return cmXMLSafe(value).Quotes(false); 94 } 95 SafeContent(std::string const & value)96 static cmXMLSafe SafeContent(std::string const& value) 97 { 98 return cmXMLSafe(value).Quotes(false); 99 } 100 101 /* 102 * Convert a std::chrono::system::time_point to the number of seconds since 103 * the UN*X epoch. 104 * 105 * It would be tempting to convert a time_point to number of seconds by 106 * using time_since_epoch(). Unfortunately the C++11 standard does not 107 * specify what the epoch of the system_clock must be. 108 * Therefore we must assume it is an arbitrary point in time. Instead of this 109 * method, it is recommended to convert it by means of the to_time_t method. 110 */ SafeContent(std::chrono::system_clock::time_point const & value)111 static std::time_t SafeContent( 112 std::chrono::system_clock::time_point const& value) 113 { 114 return std::chrono::system_clock::to_time_t(value); 115 } 116 117 template <typename T> SafeContent(T value)118 static T SafeContent(T value) 119 { 120 return value; 121 } 122 123 std::ostream& Output; 124 std::stack<std::string, std::vector<std::string>> Elements; 125 std::string IndentationElement; 126 std::size_t Level; 127 std::size_t Indent; 128 bool ElementOpen; 129 bool BreakAttrib; 130 bool IsContent; 131 }; 132 133 class cmXMLElement; // IWYU pragma: keep 134 135 class cmXMLDocument 136 { 137 public: cmXMLDocument(cmXMLWriter & xml)138 cmXMLDocument(cmXMLWriter& xml) 139 : xmlwr(xml) 140 { 141 this->xmlwr.StartDocument(); 142 } ~cmXMLDocument()143 ~cmXMLDocument() { this->xmlwr.EndDocument(); } 144 cmXMLDocument(const cmXMLDocument&) = delete; 145 cmXMLDocument& operator=(const cmXMLDocument&) = delete; 146 147 private: 148 friend class cmXMLElement; 149 cmXMLWriter& xmlwr; 150 }; 151 152 class cmXMLElement 153 { 154 public: cmXMLElement(cmXMLWriter & xml,const char * tag)155 cmXMLElement(cmXMLWriter& xml, const char* tag) 156 : xmlwr(xml) 157 { 158 this->xmlwr.StartElement(tag); 159 } cmXMLElement(cmXMLElement & par,const char * tag)160 cmXMLElement(cmXMLElement& par, const char* tag) 161 : xmlwr(par.xmlwr) 162 { 163 this->xmlwr.StartElement(tag); 164 } cmXMLElement(cmXMLDocument & doc,const char * tag)165 cmXMLElement(cmXMLDocument& doc, const char* tag) 166 : xmlwr(doc.xmlwr) 167 { 168 this->xmlwr.StartElement(tag); 169 } ~cmXMLElement()170 ~cmXMLElement() { this->xmlwr.EndElement(); } 171 172 cmXMLElement(const cmXMLElement&) = delete; 173 cmXMLElement& operator=(const cmXMLElement&) = delete; 174 175 template <typename T> Attribute(const char * name,T const & value)176 cmXMLElement& Attribute(const char* name, T const& value) 177 { 178 this->xmlwr.Attribute(name, value); 179 return *this; 180 } 181 template <typename T> Content(T const & content)182 void Content(T const& content) 183 { 184 this->xmlwr.Content(content); 185 } 186 template <typename T> Element(std::string const & name,T const & value)187 void Element(std::string const& name, T const& value) 188 { 189 this->xmlwr.Element(name, value); 190 } Comment(const char * comment)191 void Comment(const char* comment) { this->xmlwr.Comment(comment); } 192 193 private: 194 cmXMLWriter& xmlwr; 195 }; 196