• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gn/xml_element_writer.h"
6 
7 #include <memory>
8 
9 XmlAttributes::XmlAttributes() = default;
10 
XmlAttributes(std::string_view attr_key,std::string_view attr_value)11 XmlAttributes::XmlAttributes(std::string_view attr_key,
12                              std::string_view attr_value) {
13   add(attr_key, attr_value);
14 }
15 
add(std::string_view attr_key,std::string_view attr_value)16 XmlAttributes& XmlAttributes::add(std::string_view attr_key,
17                                   std::string_view attr_value) {
18   push_back(std::make_pair(attr_key, attr_value));
19   return *this;
20 }
21 
XmlElementWriter(std::ostream & out,const std::string & tag,const XmlAttributes & attributes)22 XmlElementWriter::XmlElementWriter(std::ostream& out,
23                                    const std::string& tag,
24                                    const XmlAttributes& attributes)
25     : XmlElementWriter(out, tag, attributes, 0) {}
26 
XmlElementWriter(std::ostream & out,const std::string & tag,const XmlAttributes & attributes,int indent)27 XmlElementWriter::XmlElementWriter(std::ostream& out,
28                                    const std::string& tag,
29                                    const XmlAttributes& attributes,
30                                    int indent)
31     : out_(out),
32       tag_(tag),
33       indent_(indent),
34       opening_tag_finished_(false),
35       one_line_(true) {
36   out << std::string(indent, ' ') << '<' << tag;
37   for (auto attribute : attributes)
38     out << ' ' << attribute.first << "=\"" << attribute.second << '"';
39 }
40 
~XmlElementWriter()41 XmlElementWriter::~XmlElementWriter() {
42   if (!opening_tag_finished_) {
43     // The XML spec does not require a space before the closing slash. However,
44     // Eclipse is unable to parse XML settings files if there is no space.
45     out_ << " />" << std::endl;
46   } else {
47     if (!one_line_)
48       out_ << std::string(indent_, ' ');
49     out_ << "</" << tag_ << '>' << std::endl;
50   }
51 }
52 
Text(std::string_view content)53 void XmlElementWriter::Text(std::string_view content) {
54   StartContent(false);
55   out_ << content;
56 }
57 
SubElement(const std::string & tag)58 std::unique_ptr<XmlElementWriter> XmlElementWriter::SubElement(
59     const std::string& tag) {
60   return SubElement(tag, XmlAttributes());
61 }
62 
SubElement(const std::string & tag,const XmlAttributes & attributes)63 std::unique_ptr<XmlElementWriter> XmlElementWriter::SubElement(
64     const std::string& tag,
65     const XmlAttributes& attributes) {
66   StartContent(true);
67   return std::make_unique<XmlElementWriter>(out_, tag, attributes, indent_ + 2);
68 }
69 
StartContent(bool start_new_line)70 std::ostream& XmlElementWriter::StartContent(bool start_new_line) {
71   if (!opening_tag_finished_) {
72     out_ << '>';
73     opening_tag_finished_ = true;
74 
75     if (start_new_line && one_line_) {
76       out_ << std::endl;
77       one_line_ = false;
78     }
79   }
80 
81   return out_;
82 }
83 
XmlEscape(const std::string & value)84 std::string XmlEscape(const std::string& value) {
85   std::string result;
86   for (char c : value) {
87     switch (c) {
88       case '\n':
89         result += "&#10;";
90         break;
91       case '\r':
92         result += "&#13;";
93         break;
94       case '\t':
95         result += "&#9;";
96         break;
97       case '"':
98         result += "&quot;";
99         break;
100       case '<':
101         result += "&lt;";
102         break;
103       case '>':
104         result += "&gt;";
105         break;
106       case '&':
107         result += "&amp;";
108         break;
109       default:
110         result += c;
111     }
112   }
113   return result;
114 }
115